跳转到主要内容

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 函数”之间的差距尽可能接近零。其他一切——上下文管理、工具执行、类型解析——都是实现细节,你可以忽略它们直到需要自定义。 当你确实需要自定义时,上下文模型给你完全的控制。但默认就是:写一个函数。