|
Function Calling 让大模型连接真实世界/业务系统,三步流程(把 AI 当人看):
```text
1. LLM 读工具清单(schema) → 判断"要不要调、调哪个" (≈人读API文档+读需求)
2. 生成调用参数(arguments JSON) (≈人写调用代码)
3. 外层程序真正执行函数 → 结果回填 → LLM 整合回答 (≈人运行程序+整理结论)
```
注意:蒸馏版/部分本地模型不支持原生 func call,但可用自定义 prompt 实现(见 tpf 双引擎)。
典型应用:RAG 检索触发、结构化入库、调用外部 API/启动服务等。
|
|
OpenAI 标准 tools 定义(四要素 + strict):
```python
tools = [{
"type": "function",
"function": {
"name": "get_location_coordinate",
"description": "根据地点描述获取经纬度",
"parameters": {
"type": "object",
"properties": {
"location": {"type": "string", "description": "地点名,如 五道口"},
"region": {"type": "string", "description": "所在城市"}
},
"required": ["location"],
"additionalProperties": False # strict 模式必须显式给出
},
"strict": True
}
}]
resp = client.chat.completions.create(model="gpt-4o", messages=..., tools=tools)
for tc in resp.choices[0].message.tool_calls:
args = json.loads(tc.function.arguments) # LLM 生成的参数
result = dispatch(tc.function.name, args) # 真正执行
messages.append({"role":"tool","tool_call_id":tc.id,"content":json.dumps(result)})
```
回填用 `role="tool"` + `tool_call_id`,再发起第二次请求让模型整合。
|
|
func call 对模型的三大能力要求:
1. **问题理解与行动规划**(思维链):先想清楚分几步、每步用哪个工具
2. **结构化输出**:arguments 必须是合法 JSON,字段符合 schema
3. **上下文理解**:工具返回结果要能读懂并整合进最终回答
链式场景(查坐标→搜周边POI)依赖模型自主传递中间结果——这正是 Agent 的雏形。
|
|
tpf 的注册机制——`register_function(*, name, description, parameters, function)` 维护**双映射**:
- `_function_infos`:喂给 prompt 的工具清单(OpenAI 格式)
- `_function_mappings`:name → 真实函数对象,执行时 `json.loads(arguments)` 后调用
```python
from tpf.llm import MyChat
chat = MyChat(env_file="env.txt")
func_dcn = {
"name": "dcn_start_service",
"description": "启动指定服务器的dcn服务",
"parameters": {"type": "object",
"properties": {"host": {"type": "string", "description": "主机名"}}},
}
chat.register_function(**func_dcn, function=lambda host: start(host))
print(chat.tool_list()) # 查看已注册清单
print(chat.prompt_system()) # 查看注入 prompt 的系统提示(含工具列表+输出格式+示例)
```
|
|
`prompt_system()` 是"自定义 func call"的核心模板(适用于不支持原生 tools 的模型):
```text
你可以调用以下内部函数:
{函数名}({参数}): {描述}
...
#输出格式:
{"name": 函数名, "arguments": {参数dict}, "description": 调用描述}
#示例
{若干 ask/answer 示例}
```
用户侧 `prompt_user()` 还会附加 5 条"输出前思考"检查清单(是否需要函数、参数是否齐全、能否直接回答等)。
|
|
链式注册两个函数完成复合任务:
```python
from tpf.llm import FuncCall
fc = FuncCall()
fc.register_function(name="get_location_coordinate", description="获取地点经纬度",
parameters={"type":"object","properties":{
"location":{"type":"string"},"region":{"type":"string"}},
"required":["location"]},
function=get_coordinate)
fc.register_function(name="search_nearby_pois", description="搜索周边兴趣点",
parameters={"type":"object","properties":{
"keyword":{"type":"string"},"latitude":{"type":"number"},"longitude":{"type":"number"}},
"required":["keyword","latitude","longitude"]},
function=search_pois)
res = fc.chat("五道口附近的咖啡馆",
model_list=["gpt-4o", "DeepSeek-R1-14B-Q8:latest"],
func_index=0, answer_index=0)
```
`func_index`:负责"判断+调函数"的模型下标;`answer_index`:负责"整合结果作答"的模型下标(None 时默认等于 func_index,可直接返回函数结果)。
|
|
`FuncCall.chat()` / `MyChat.*_func_call()` 的统一两段式:
```text
路径A(在线/原生tools):_request() 走 OpenAI tools 协议
create(tools=...) → tool_calls → _call() 执行 → role=tool 回填 → 整合
路径B(本地ollama模型):prompt_system() + prompt_user() 注入工具清单
→ chat() 对话 → 模型输出 ```json``` 工具调用 → tools_call() 逐个执行
```
第二段"整合作答"提示词核心:
```text
#用户输入:{query}
#内部函数调用返回的结果:{func_call_res}
请结合用户输入的问题以及内部函数调用结果回答,
- 简洁风格,不思考,不推理
#输出格式:{"query":..., "result":...}
```
|
|
本地 ollama 模型走自定义流程的配置:
```python
chat.set_local_model("DeepSeek-R1-14B-Q8:latest") # 注册进本地名单
# answer 模型若是本地模型 → 一次请求内完成(消息里带 tool 结果)
response = chat.func_call(query, model_list=[...], func_index=3, answer_index=2,
base_url='http://localhost:11434/v1/')
```
`tools_call()` 解析失败时打印原文并退出(sys.exit)——生产使用建议改为重试。
|
|
两个高频工具模式:
**sqlite 查询**(func call 的经典练习题):
```python
from tpf.db import SqLite
sdb = SqLite(db='vo.db')
df = sdb.select("select * from user", columns=["id","name","age"])
```
**代码执行**(给 agent 的"计算器",带安全边界):
```python
from tpf.box import zx
res1 = zx.check_grammar_noexec(code) # 仅语法检查 → {'status':'ok'}
res2 = zx.exec_python_code(source) # subprocess+tempfile+timeout=10 → {'status':'ok','result':'(2, 2)'}
```
timeout 防死循环 + 只回传结果字符串,是"让 LLM 用工具而非自己算"的典型设计。
|
Function Calling 官方文档