Documentation Index
Fetch the complete documentation index at: https://simplellmfunc.cn/llms.txt
Use this file to discover all available pages before exploring further.
LLM 即函数
SimpleLLMFunc 的核心洞察:LLM 调用应该与 Python 函数调用无法区分。
现有方案的问题
大多数 LLM 框架在你和模型之间引入了新的抽象:
- 链式框架让你以链接步骤的方式思考,每一步通过框架定义的协议向下一步传递数据
- 图框架让你定义节点和边,通过可视化 DAG 路由数据
- Agent 框架将 LLM 隐藏在一个管理自身状态的”代理”抽象背后
所有这些都在你的意图和模型之间放置了一层框架特定的概念。你在学习框架的词汇,而不是直接表达你的任务。
函数模型
在 SimpleLLMFunc 中,LLM 调用就是函数调用:
@llm_function(llm_interface=llm)
async def extract_entities(text: str) -> list[Entity]:
"""从文本中提取命名实体。包括人物、组织和地点类型。"""
pass
这是一个完整的、可运行的程序。这个函数:
- 有名称 —
extract_entities
- 有类型化参数 —
text: str
- 有类型化返回值 —
list[Entity]
- 有文档字符串描述行为 — 这就是提示词
- 是可等待的 —
await extract_entities("...")
- 是可组合的 — 从其他函数调用它、传递它、测试它
没有”链”,没有”节点”,没有”Agent 对象”。只有函数。
你获得什么
边界处的类型安全
返回类型注解是一个契约。框架确保 LLM 输出被解析为你声明的类型——否则抛出明确的错误。不需要手动 JSON 解析,不会”有时模型返回字符串而不是对象”。
class Analysis(BaseModel):
sentiment: Literal["positive", "negative", "neutral"]
confidence: float = Field(ge=0.0, le=1.0)
reasoning: str
result: Analysis = await analyze(text) # 类型检查,结构保证
可组合性
函数天然可组合。用普通 Python 构建复杂管道:
async def full_pipeline(document: str) -> Report:
entities = await extract_entities(document)
summary = await summarize(document)
sentiment = await analyze_sentiment(document)
return Report(entities=entities, summary=summary, sentiment=sentiment)
不需要框架 DSL。不需要链定义。只是函数调用函数。
可测试性
像任何其他函数一样 mock 它:
async def test_pipeline():
with mock.patch("my_module.extract_entities") as mock_extract:
mock_extract.return_value = [Entity(name="Alice", type="person")]
result = await full_pipeline("Alice went to Paris.")
assert result.entities[0].name == "Alice"
IDE 支持
你的 IDE 已经知道如何处理异步函数、类型注解和文档字符串。自动补全、跳转到定义、内联文档——全部免费。
扩展:LLM 即 Agent
@llm_chat 将函数模型扩展到多轮 Agent。Agent 仍然只是一个函数——它接受输入,返回输出。区别在于它可以使用工具并维护对话状态:
@llm_chat(llm_interface=llm, toolkit=[search, calculate], stream=True)
async def research_agent(question: str, history: list | None = None):
"""研究问题,使用可用工具。引用你的来源。"""
pass
相同的函数接口。相同的可组合性。但现在函数可以在内部跨多个步骤推理(ReAct 循环),使用工具,并流式传输结果。
关键洞察
框架的工作是让”我想调用 LLM”和”我调用了一个 Python 函数”之间的差距尽可能接近零。其他一切——上下文管理、工具执行、类型解析——都是实现细节,你可以忽略它们直到需要自定义。
当你确实需要自定义时,上下文模型给你完全的控制。但默认就是:写一个函数。