工具无需复杂。其核心只是来自你的大语言模型 (LLM) 的结构化输出,用于触发确定性代码。
例如,假设你有两个工具 CreateIssue
和 SearchIssues
。要求一个大语言模型 (LLM) “使用多个工具之一”,其实就是要求它输出一个我们可以解析为代表这些工具的对象的 JSON。
class Issue:
title: str
description: str
team_id: str
assignee_id: str
class CreateIssue:
intent: "create_issue"
issue: Issue
class SearchIssues:
intent: "search_issues"
query: str
what_youre_looking_for: str
这个模式很简单:
- 大语言模型 (LLM) 输出结构化的 JSON
- 确定性代码执行相应的操作 (例如调用外部 API)
- 捕获结果并反馈到上下文中
这在大语言模型 (LLM) 的决策和你的应用程序的操作之间创建了清晰的分离。LLM 决定做什么,但你的代码控制如何做。仅仅因为 LLM “调用了一个工具” 并不意味着你每次都必须以相同的方式去执行一个特定的相应函数。
如果你还记得我们上面的 switch 语句
if nextStep.intent == 'create_payment_link':
stripe.paymentlinks.create(nextStep.parameters)
return # 或者任何你想要的操作,见下文
elif nextStep.intent == 'wait_for_a_while':
# 做一些单子 (monadic) 操作之类的
else: #... 模型没有调用我们已知的工具
# 做些别的事情
注意: 关于“普通提示 (plain prompting)”、“工具调用 (tool calling)”与“JSON 模式 (JSON mode)”的优点以及各自的性能权衡,已经有很多讨论。我们很快会提供一些相关资源的链接,但这里不深入探讨。请参阅 提示 vs JSON 模式 vs 函数调用 vs 约束生成 vs SAP、我应该何时使用函数调用、结构化输出或 JSON 模式? 和 OpenAI JSON vs 函数调用。
“下一步”可能不像“运行一个纯函数并返回结果”那样原子化。当你将“工具调用”看作仅仅是模型输出一个描述确定性代码应该做什么的 JSON 时,你就能解锁极大的灵活性。将这一点与 要素 8:掌控你的控制流 结合起来。