Mirascope是一种直观的LLM构建方法。使用Mirascope构建感觉就像编写您已经习惯的Python代码。
安装
pip install mirascope
如果您使用这些功能,还可以安装额外的可选依赖项:
pip install mirascope[anthropic] # AnthropicCall, ...
pip install mirascope[groq] # GroqCall, ...
pip install mirascope[logfire] # with_logfire装饰器, ...
pip install mirascope[all] # 所有可选依赖项
注意:如果使用zsh,请转义方括号(例如
pip install mirascope\[anthropic\]
)
入门
示例
共置
共置是我们理念的核心原则之一。所有可能影响LLM调用质量的因素——从提示到模型再到温度——都必须放在一起,这样我们才能适当地对调用质量进行版本控制和测试。这很有用,因为我们拥有所有我们想要的信息,包括用于分析的元数据,这在快速开发过程中尤为重要。
import os
from mirascope import tags
from mirascope.openai import OpenAICall, OpenAICallParams
os.environ["OPENAI_API_KEY"] = "YOUR_API_KEY"
@tags(["version:0003"])
class Editor(OpenAICall):
prompt_template = """
SYSTEM:
你是一位顶级漫画编辑。
USER:
我正在构思一个新的故事情节。你觉得怎么样?
{storyline}
"""
storyline: str
call_params = OpenAICallParams(model="gpt-4", temperature=0.4)
storyline = "..."
editor = Editor(storyline=storyline)
print(editor.messages()) # 空白会自动去除
# > [{'role': 'system', 'content': '你是一位顶级漫画编辑。'}, {'role': 'user', 'content': "我正在构思一个新的故事情节。你觉得怎么样?\n..."}]
critique = editor.call()
print(critique.content)
# > 我认为开头很棒,但是...
print(editor.dump() | critique.dump())
# {
# "tags": ["version:0003"],
# "template": "SYSTEM:\n你是一位顶级漫画编辑。\n\nUSER:\n我正在构思一个新的故事情节。你觉得怎么样?\n{storyline}",
# "inputs": {"storyline": "..."},
# "start_time": 1710452778501.079,
# "end_time": 1710452779736.8418,
# "output": {
# "id": "chatcmpl-92nBykcXyTpxwAbTEM5BOKp99fVmv",
# "choices": [
# {
# "finish_reason": "stop",
# "index": 0,
# "logprobs": None,
# "message": {
# "content": "我认为开头很棒,但是...",
# "role": "assistant",
# "function_call": None,
# "tool_calls": None,
# },
# }
# ],
# "created": 1710452778,
# "model": "gpt-4-0613",
# "object": "chat.completion",
# "system_fingerprint": None,
# "usage": {"completion_tokens": 25, "prompt_tokens": 33, "total_tokens": 58},
# },
# }
聊天历史
我们的模板解析器使插入聊天历史变得非常简单:
from openai.types.chat import ChatCompletionMessageParam
from mirascope.openai import OpenAICall
class Librarian(OpenAICall):
prompt_template = """
SYSTEM: 你是世界上最伟大的图书管理员。
MESSAGES: {history}
USER: {question}
"""
question: str
history: list[ChatCompletionMessageParam] = []
librarian = Librarian(question="", history=[])
while True:
librarian.question = input("(用户): ")
response = librarian.call()
librarian.history += [
{"role": "user", "content": librarian.question},
{"role": "assistant", "content": response.content},
]
print(f"(助手): {response.content}")
#> (用户): 我应该读什么奇幻小说?
#> (助手): 你读过《风之名》吗?
#> (用户): 读过!你喜欢它的什么?
#> (助手): 我喜欢它复杂的世界构建...
工具(函数调用)
我们已经使实现和使用工具(函数调用)变得直观:
from typing import Literal
from mirascope.openai import OpenAICall, OpenAICallParams
def get_current_weather(
location: str, unit: Literal["celsius", "fahrenheit"] = "fahrenheit"
):
"""获取给定位置的当前天气。"""
if "tokyo" in location.lower():
print(f"东京,日本现在是{unit}10度")
elif "san francisco" in location.lower():
print(f"旧金山,加利福尼亚现在是{unit}72度")
elif "paris" in location.lower():
print(f"巴黎,法国现在是{unit}22度")
else:
print(f"我不确定{location}的天气如何")
class Forecast(OpenAICall):
prompt_template = "东京的天气如何?"
call_params = OpenAICallParams(model="gpt-4", tools=[get_current_weather])
tool = Forecast().call().tool
if tool:
tool.fn(**tool.args)
#> 东京,日本现在是华氏10度
链式调用
链式调用多个调用就像编写一个属性一样简单:
import os
from functools import cached_property
from mirascope.openai import OpenAICall
from pydantic import computed_field
os.environ["OPENAI_API_KEY"] = "YOUR_API_KEY"
class ChefSelector(OpenAICall):
prompt_template = """
命名一位擅长烹饪{food_type}食物的厨师。
只给我名字。
"""
food_type: str
class RecipeRecommender(ChefSelector):
prompt_template = """
系统:
想象你是厨师{chef}。
你的任务是推荐你,{chef},会兴奋地提供的食谱。
用户:
推荐一道使用{ingredient}的食谱。
"""
ingredient: str
@computed_field
@cached_property
def chef(self) -> str:
"""使用`ChefSelector`根据食物类型选择厨师。"""
return ChefSelector(food_type=self.food_type).call().content
recommender = RecipeRecommender(food_type="japanese", ingredient="apples")
recipe = recommender.call()
print(recipe.content)
# > 当然!这里有一道美味清爽的日式苹果沙拉食谱:...
当然,你也可以通过顺序而不是属性来链式调用,并将链式调用包装在一个函数中以便重复使用。你可以在这里找到这种方式的示例。
提取结构化信息
在工具之上构建的便利功能,使提取结构化信息变得可靠:
from typing import Literal, Type
from mirascope.openai import OpenAIExtractor
from pydantic import BaseModel
class TaskDetails(BaseModel):
description: str
due_date: str
priority: Literal["low", "normal", "high"]
class TaskExtractor(OpenAIExtractor[TaskDetails]):
extract_schema: Type[TaskDetails] = TaskDetails
prompt_template = """
从以下任务中提取任务详情:
{task}
"""
task: str
task = "在下周五之前提交季度报告。任务优先级高。"
task_details = TaskExtractor(task=task).extract()
assert isinstance(task_details, TaskDetails)
print(task_details)
#> description='提交季度报告' due_date='下周五' priority='high'
FastAPI集成
由于我们在Pydantic的基础上构建了BasePrompt
,我们可以直接集成像FastAPI这样的工具:
import os
from typing import Type
from fastapi import FastAPI
from mirascope.openai import OpenAIExtractor
from pydantic import BaseModel
os.environ["OPENAI_API_KEY"] = "YOUR_OPENAI_API_KEY"
app = FastAPI()
class Book(BaseModel):
title: str
author: str
class BookRecommender(OpenAIExtractor[Book]):
extract_schema: Type[Book] = Book
prompt_template = "请推荐一本{genre}类型的书。"
genre: str
@app.post("/")
def root(book_recommender: BookRecommender) -> Book:
"""根据提供的`genre`生成一本书。"""
return book_recommender.extract()
支持的提供商和集成
你可以在我们的文档中找到支持的提供商列表,以及如何在Mirascope中使用它们的示例。
我们正在不断努力,以尽可能无缝地将Mirascope与尽可能多的工具进行集成。你可以在我们的文档中找到我们当前支持的集成。如果你有任何想要的集成,请告诉我们!
路线图
- 代理
- 简单的工具调用和执行
- 更多关于TOOL消息的便利功能
- ReAct代理的基类
- 查询规划代理的基类
- 大量示例...
- RAG
- ChromaDB
- Pinecone
- OpenAI嵌入
- Cohere嵌入
- Hugging Face
- 大量示例...
- Mirascope CLI
- 提示/调用/提取器的版本控制
- RAG CLI(例如,版本控制存储,一次性向量存储交互)
- 与LLMOps工具的集成版本控制(例如Weave,LangSmith,...)
- LLM提供商自动转换
- 模板(
mirascope from_template pinecone_rag_openai_call my_call_name
)
- 使用LLM提取结构化信息
- 工具的流式提取(函数调用)
- 更复杂消息的附加模板解析
- 聊天历史
- 列表 + 列表[列表]便利性
- 附加元数据
- 视觉
- 支持更多LLM提供商:
- Anthropic
- Cohere
- Mistral
- Groq
- Gemini
- HuggingFace
- 集成
- Logfire by Pydantic
- Langfuse
- Weights & Biases Trace
- Weave by Weights & Biases
- LangChain / LangSmith
- ...告诉我们你想要集成什么!
- 评估提示及其质量(按版本)
版本控制
Mirascope使用语义版本控制。
许可证
本项目根据MIT许可证的条款授权。