当能力或 API 被 LLM / Agent 调用时,是否容易被模型理解、是否便于稳定调用 ,往往直接决定这套能力会不会被选对、用对。本系列围绕「让 AI 更好理解、更好调用 」这一主线,聚焦面向 LLM / Agent 的接口与数据设计 ------从 API 契约、工具与 Schema、提示与错误模型,到安全幂等、可观测性与生产实践,系统讨论如何把接口与描述设计得更好,以减少误选、误用与幻觉,并更顺地落到工程环境。本篇为系列开篇,从「通用一问一答式接口」与「能力端点」的对比切入,建立后续各篇的共同语境。
摘要 :直接暴露「问一句答一句」的通用接口(如 /ask)会让 LLM 难以稳定选对能力、输入输出语义模糊。用能力化端点 (如 /summarize-document、/list-orders-by-user)替代通用对话接口,可以约束输入输出与语义,便于模型选对能力、减少幻觉与误用。本文说明动机、设计原则,并给出可运行的示例项目。
关键词:LLM API 设计;能力端点;REST;Agent 调用;接口契约
代码链接:面向 LLM 的程序设计 1:API 契约设计示例代码
1 为什么通用「问一句答一句」接口不适合被 LLM 调用?
很多系统会对外提供一个「万能」接口:用户或调用方发一段自然语言,系统用大模型生成回复并返回。例如:
POST /chat或POST /ask:请求体{ "message": "用户问题" },响应为{ "reply": "模型生成的回答" }。
对人来说,这种接口简单直观;但对被 LLM/Agent 调用的下游 API 而言,存在明显问题:
- 能力不可区分:调用方(另一个 LLM)只能看到「一个会说话的黑盒」,无法从接口语义上区分「这是做摘要的」「这是查订单的」还是「这是写邮件的」。模型需要从文档或示例中猜测,容易选错或重复造轮子。
- 输入输出无契约:请求和响应都是自由文本或简单键,没有结构化约束。模型可能传入无关参数或漏传必要信息,响应也可能难以被程序化解析(例如混入解释性文字)。
- 难以编排与重试:多步工作流中,上一步的输出要作为下一步的输入。若每一步都是「自然语言进、自然语言出」,中间结果难以稳定解析,重试与错误处理也缺乏明确边界。
因此,面向「被 AI 调用」的 API,更稳妥的做法是:把能力拆成独立、语义明确的能力端点,每个端点对应一类确定性的输入/输出契约。
2 什么是「能力端点」?
能力端点 指的是:每个 HTTP 端点对应一类明确的能力 ,且请求与响应都有清晰、可校验的结构(通常为 JSON Schema)。
| 对比项 | 通用接口(如 /ask) |
能力端点(如 /summarize-document) |
|---|---|---|
| 语义 | 模糊:「问什么答什么」 | 明确:「对文档做摘要」 |
| 输入 | 自由文本或少量键 | 结构化:如 document_id、max_length |
| 输出 | 自由文本 | 结构化:如 summary、word_count |
| 模型选路 | 需从文档推断 | 可从路径/名称直接对应到能力 |
示例(概念层面):
POST /summarize-document:输入{ "document_id": "xxx", "max_length": 200 },输出{ "summary": "...", "word_count": 42 }。POST /list-orders-by-user:输入{ "user_id": "xxx", "status": "pending", "limit": 10 },输出{ "orders": [...], "total": 5 }。
这样,当 LLM 需要「查用户订单」时,可以直接选择 list-orders-by-user 并按照约定传参,而不是向一个通用的「聊天」接口发一句自然语言再解析回复。
3 设计原则小结
- 一端点一能力 :每个 URL 对应一种明确能力,路径名即语义(如
summarize-document、list-orders-by-user)。 - 输入输出结构化:请求体、响应体使用 JSON,并尽量用固定字段名与类型(后续可配合 JSON Schema/OpenAPI 做严格约束,见本系列第二篇)。
- 命名稳定、可发现:路径与字段名一旦对外暴露,尽量保持兼容;新增能力用新端点而非在旧端点上堆参数。
4 本示例在做什么?
本主题配套的 demo 实现了一个对比示例:
- 通用接口 :
POST /ask,请求{ "message": "..." },响应{ "reply": "..." },语义与结构均模糊。 - 能力端点 :
POST /summarize-document:传入document_id、可选max_length,返回summary、word_count。POST /list-orders-by-user:传入user_id、可选status、limit,返回orders列表与total。
通过同一套服务同时提供两种风格,便于在文档或博客中对比「通用接口」与「能力端点」在可发现性、参数清晰度、响应可解析性上的差异。Demo 使用 FastAPI 实现,提供 OpenAPI 文档,并配有运行说明与完整方案文档。

当我们通过 uvicorn server_api:app --reload --host 127.0.0.1 --port 8310 启动服务后,再在另外一个terminal中运行 python main.py,terminal中返回:
=== 1. 通用接口 POST /ask ===
请求: {"message": "帮我查一下 user_001 的订单"}
响应: {'reply': '您可以提供用户 ID 和状态筛选条件,我会帮您查询订单列表。'}
请求: {"message": "给 doc_001 做个摘要"}
响应: {'reply': '请提供文档 ID,我可以为您生成摘要。'}
=== 2. 能力端点 POST /list-orders-by-user ===
请求: {"user_id": "user_001", "status": "pending", "limit": 5}
响应: {'orders': [{'order_id': 'ord_1', 'amount': 99.0, 'status': 'pending'}], 'total': 1}
=== 3. 能力端点 POST /summarize-document ===
请求: {"document_id": "doc_001", "max_length": 100}
响应: {'summary': '人工智能在自然语言处理领域取得显著进展。大语言模型能够完成摘要、问答、翻译等任务。企业可将 LLM 与内部 API 结合,构建智能客服与数据分析应用。', 'word_count': 75}
5 完整代码与文档
- 运行与架构 :demo/README_运行与架构.md --- 环境、安装、配置、如何启动、项目结构、源码说明。
- 完整方案 :demo/README_完整方案.md --- 方案背景、设计思路、接口对比、典型请求示例与结果说明。
在项目目录 demo/ 下执行 pip install -r requirements.txt 并配置 .env 后,运行 uvicorn server_api:app --reload 即可在本地体验上述接口。