news 2026/9/8 12:52:56

一次业务建模,双端消费:用Function Calling让AI读懂业务

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
一次业务建模,双端消费:用Function Calling让AI读懂业务

现在很多团队都在做 AI 应用,但最常遇到的困境不是模型能力不够,而是业务逻辑不知道该以什么形式交给 AI。提示词写了一大堆,模型还是答非所问;给 AI 开放数据库,又怕它生成出危险 SQL。本文围绕“Model your business once – for humans and AI alike”这一理念,从业务建模的视角出发,完整拆解如何把业务知识沉淀为一套结构化的模型,既服务于传统业务系统,也能直接被 AI Agent 消费。

文章会先讲清楚核心概念,再以真实项目为例,演示从业务结构定义、语义层搭建到 Function Calling 调用的完整链路,最后给出常见问题排查和工程落地建议。全文包含可直接复制的代码示例,无论是正在做 AI 应用开发的工程师,还是想要沉淀业务资产的技术负责人,都可以作为参考。

1. 背景与核心概念

1.1 一句话理解:一套模型,两种消费者

“Model your business once – for humans and AI alike” 这句话的核心意思是:用同一种业务模型,同时服务于人和 AI

传统开发模式下,业务模型主要服务于人——给后端程序员写接口,给前端同学画页面,给产品经理核对流程。AI 介入之后,大家第一反应往往是把业务规则写成大段提示词塞给模型,结果提示词越来越长,越来越难以维护,换一个模型就要重写一遍。

更合理的思路是:业务知识本身不依赖任何大模型,它是一套结构化的、关于业务对象、业务规则和业务流程的描述。人和 AI 只是这套模型的不同消费者。

举个例子:

  • 人的消费者:前端表单根据模型渲染报销单字段。
  • AI 的消费者:模型根据“报销单”结构识别用户请求中的实体,并调用对应业务函数完成查询。

同一份模型,不需要为 AI 单独维护一套克隆版本。

1.2 为什么传统知识库方式走不通

很多团队在落地 AI 功能时,通常有几种常见的做法:

方案优点痛点
把业务规则写进提示词直观、见效快提示词过长、维护困难、模型升级后行为漂移
直接给 AI 数据库连接权限减少开发量存在 SQL 注入和数据越权风险,模型可能生成错误查询
为 AI 单独写一套接口文档职责清晰业务改动时需要同步维护两套内容,容易遗漏
把业务知识向量化后 RAG 检索能回答开放问题查询类、操作类任务准确性不足,不适合精确计算

这些方案的共同问题在于:人和 AI 看到的不是同一份业务现实

当业务规则发生变化时,要么忘了更新 AI 侧的资料,要么提示词和代码逻辑出现冲突。所谓“Model your business once”,就是要把业务模型变成唯一事实源(Single Source of Truth),人和 AI 都从这一份模型上获取对业务的一致理解。

1.3 AI 工程实践中的定位

在大模型应用架构中,这个理念处于一个非常关键的位置。传统 AI 应用架构通常包括:

  • 模型层:大语言模型本身。
  • 应用层:Prompt 模板、Agent 编排、工具调用。
  • 数据层:业务数据库、向量库、文档。

模型层和应用层之间,往往缺一个业务语义层。这个语义层的作用是:

  • 把数据库表结构翻译成业务概念。
  • 把业务规则从自然语言转成结构化定义。
  • 让 AI Agent 能够理解“有哪些业务能力可以被调用”。

这就是阿里巴巴提出的“半成品应用”思路中非常重视的环节:AI 应用真正工程化的瓶颈,不在模型调参,而在业务知识的可编程、可复用、可验证。业务建模一次,AI 侧和 Web 侧共享模型,是 AI 应用走向生产环境的必经之路。

2. 环境准备与版本说明

2.1 技术选型

本文实战示例采用以下技术组合,你可以根据自己项目的实际情况调整版本,但整体思路可以直接复用:

组件选型建议说明
编程语言Python 3.10+AI 生态支持最好,示例代码简洁
LLM APIOpenAI 兼容接口Function Calling 能力成熟,国内多家厂商也兼容这套协议
数据存储SQLite(演示)/ PostgreSQL(生产)避免环境过度复杂,示例采用 SQLite
业务建模JSON Schema跨语言、跨平台,人和 AI 都能解析
调用协议OpenAPI 风格定义描述业务能力边界与入参出参
开发 IDEVS Code / JetBrains 系列无特殊要求

2.2 安装依赖

# 创建虚拟环境 python -m venv .venr source .venr/bin/activate # Windows 下执行 .venr\Scripts\activate # 安装核心依赖 pip install openai flask pydantic jsonschema sqlite-utils

版本需要根据你的项目实际情况调整,重点演示的是“如何建模”和“如何对接模型”,不绑定特定版本号。

2.3 示例项目结构

为了让后续内容更清晰,我们先规划好项目目录:

business-model/ ├── app.py # Flask 入口,模拟业务系统接口 ├── business_model/ │ ├── __init__.py │ ├── schema.py # JSON Schema 业务模型定义 │ ├── semantic.py # 语义层:自然语言到结构化调用的翻译 │ ├── tools.py # AI Agent 可调用的业务函数 │ └── db.py # 数据库访问层 ├── model_consumer.py # 演示 AI Agent 如何消费业务模型 └── data/ └── business.db # SQLite 数据文件

3. 核心原理拆解

3.1 业务模型的三层结构

要做到“一次建模,双端消费”,业务模型至少包含三个层次:

第一层:业务对象模型

描述业务中涉及的核心实体,例如“客户”“订单”“报销单”“审批记录”。这一层不关心存储细节,只关心业务结构。

{ "type": "object", "properties": { "order_id": { "type": "string", "description": "订单编号,全局唯一" }, "customer_name": { "type": "string", "description": "客户姓名" }, "amount": { "type": "number", "description": "订单金额,单位元" }, "status": { "type": "string", "enum": ["pending", "paid", "shipped", "cancelled"], "description": "订单状态" }, "created_at": { "type": "string", "format": "date-time", "description": "创建时间" } }, "required": ["order_id", "amount", "status"] }

这段 JSON Schema 就是人和 AI 共享的业务对象契约。人可以直接阅读字段名和注释,AI 可以在 Function Calling 中使用该结构解析用户查询中的实体。

第二层:业务能力模型

描述系统对外提供的业务操作,比如“查询订单”“创建审批”“修改库存”。能力模型需要说清楚:

  • 这个操作叫什么?
  • 入参是什么?
  • 出参是什么?
  • 有什么约束或权限要求?

第三层:语义映射关系

这是自然语言和业务模型的桥梁。用户的提问是“上个月卖了多少货”,业务能力是query_sales,语义层负责完成这次翻译。它可以基于 LLM 实现,也可以基于规则,生产中通常两者结合。

3.2 Function Calling:AI 调用业务模型的标准方式

OpenAI 提出的 Function Calling(函数调用)已经成为行业事实标准。它的工作流程是:

  1. 系统把可用业务函数的结构化描述发给模型。
  2. 用户输入自然语言问题。
  3. 模型判断需要调用哪个函数,并生成结构化参数。
  4. 应用层执行该函数,返回真实业务数据。
  5. 模型根据返回数据组织最终回答。

这一过程中,业务模型以 JSON Schema 的形式传递给大模型。模型不需要理解业务系统的内部实现,只需要按照 Schema 生成调用参数。这正是“模型业务一次,AI 使用”的核心机制。

3.3 与 RAG 方案的分工

很多同学会问:业务模型和 RAG 有什么关系?

RAG 适合回答“知识型问题”——比如公司制度是什么、某个产品功能怎么使用。这类问题没有精确答案,适合从文档中检索生成。

而业务模型适合“操作型和查询型问题”——比如“查询订单状态”“创建审批单”“计算报销总额”。这类问题有精确的业务语义,必须调用真实函数,不能靠 LLM 编造。

两者的分工可以理解为:

问题类型适合方案示例
模糊知识RAG差旅报销标准是多少?
精确查询业务模型 + Function Calling张三上个月报销了多少钱?
操作执行业务模型 + Function Calling帮我提交一笔 300 元的报销单
跨领域分析RAG + 业务模型混合对比近三个月各团队报销趋势

4. 完整实战案例:差旅报销业务建模

下面我们通过一个真实的业务场景——差旅报销——来演示完整落地过程。这个案例包含:

  • 报销业务模型定义。
  • 业务函数实现。
  • AI Agent 接入 Function Calling。
  • 运行与验证。

4.1 定义业务对象模型

首先在business_model/schema.py中定义报销单和审批单的结构。

# 文件路径:business_model/schema.py REIMBURSEMENT_SCHEMA = { "type": "object", "properties": { "reimburse_id": { "type": "string", "description": "报销单编号" }, "employee_name": { "type": "string", "description": "员工姓名" }, "department": { "type": "string", "description": "所属部门" }, "total_amount": { "type": "number", "description": "报销总金额,单位元" }, "reason": { "type": "string", "description": "报销事由" }, "status": { "type": "string", "enum": ["draft", "submitted", "approved", "rejected", "paid"], "description": "报销单状态" }, "items": { "type": "array", "items": { "type": "object", "properties": { "category": { "type": "string", "enum": ["transport", "hotel", "meal", "other"], "description": "费用类别" }, "amount": { "type": "number", "description": "单项金额" }, "description": { "type": "string", "description": "费用说明" } }, "required": ["category", "amount"] }, "description": "报销明细列表" } }, "required": ["reimburse_id", "employee_name", "total_amount", "status"] } APPROVAL_SCHEMA = { "type": "object", "properties": { "approval_id": { "type": "string", "description": "审批编号" }, "reimburse_id": { "type": "string", "description": "关联的报销单编号" }, "approver": { "type": "string", "description": "审批人姓名" }, "decision": { "type": "string", "enum": ["approved", "rejected"], "description": "审批结论" }, "comment": { "type": "string", "description": "审批意见" }, "approved_at": { "type": "string", "format": "date-time", "description": "审批时间" } }, "required": ["approval_id", "reimburse_id", "approver", "decision"] }

这里定义的REIMBURSEMENT_SCHEMAAPPROVAL_SCHEMA同时具备两个作用:

  • 后端代码可以基于它对数据做校验。
  • AI Agent 可以基于它来识别“报销量”“审批单”等业务实体,并生成正确的参数。

4.2 实现数据库访问层

接下来实现数据库访问层business_model/db.py,这里我们使用 SQLite 演示,生产环境建议替换为 PostgreSQL 或 MySQL。

# 文件路径:business_model/db.py import sqlite3 from contextlib import contextmanager DB_PATH = "data/business.db" @contextmanager def get_connection(): conn = sqlite3.connect(DB_PATH) conn.row_factory = sqlite3.Row try: yield conn conn.commit() except Exception: conn.rollback() raise finally: conn.close() def init_db(): """初始化数据库表结构。""" with get_connection() as conn: conn.executescript(""" CREATE TABLE IF NOT EXISTS reimbursements ( reimburse_id TEXT PRIMARY KEY, employee_name TEXT NOT NULL, department TEXT, total_amount REAL NOT NULL, reason TEXT, status TEXT NOT NULL, items TEXT NOT NULL ); CREATE TABLE IF NOT EXISTS approvals ( approval_id TEXT PRIMARY KEY, reimburse_id TEXT NOT NULL, approver TEXT NOT NULL, decision TEXT NOT NULL, comment TEXT, approved_at TEXT ); """)

4.3 实现业务能力函数

业务函数是 AI 可以调用的真实能力。每个函数都通过装饰器或注册表暴露描述信息,包括名称、描述、入参 Schema。

# 文件路径:business_model/tools.py import json from datetime import datetime from .db import get_connection TOOL_REGISTRY = {} def register_tool(func): """工具注册装饰器:把函数注册到 TOOL_REGISTRY。""" TOOL_REGISTRY[func.__name__] = func return func @register_tool def query_reimbursement(reimburse_id: str) -> dict: """ 根据报销单编号查询报销详情。 参数: reimburse_id: 报销单编号,例如 RB202501001 返回: 报销单完整信息 """ with get_connection() as conn: row = conn.execute( "SELECT * FROM reimbursements WHERE reimburse_id = ?", (reimburse_id,) ).fetchone() if row is None: return {"error": "报销单不存在"} return { "reimburse_id": row["reimburse_id"], "employee_name": row["employee_name"], "department": row["department"], "total_amount": row["total_amount"], "reason": row["reason"], "status": row["status"], "items": json.loads(row["items"]) } @register_tool def query_reimbursement_by_employee(employee_name: str) -> list: """ 根据员工姓名查询该员工所有报销单。 参数: employee_name: 员工姓名 返回: 报销单列表 """ with get_connection() as conn: rows = conn.execute( "SELECT * FROM reimbursements WHERE employee_name = ?", (employee_name,) ).fetchall() return [dict(row) for row in rows] @register_tool def query_approval_by_reimburse(reimburse_id: str) -> list: """ 查询指定报销单的审批记录。 参数: reimburse_id: 报销单编号 返回: 审批记录列表 """ with get_connection() as conn: rows = conn.execute( "SELECT * FROM approvals WHERE reimburse_id = ?", (reimburse_id,) ).fetchall() return [dict(row) for row in rows]

为了让 AI 正确理解这些函数,我们还需要为每个函数生成大模型能够识别的描述信息。这里把 JSON Schema 形式的入参定义和函数描述统一管理起来:

# 文件路径:business_model/tools.py 追加内容 def build_openai_tools(): """构造 OpenAI Function Calling 需要的 tools 参数。""" return [ { "type": "function", "function": { "name": "query_reimbursement", "description": "根据报销单编号查询报销详情,适用于用户询问某条报销单信息时。", "parameters": { "type": "object", "properties": { "reimburse_id": { "type": "string", "description": "报销单编号,例如 RB202501001" } }, "required": ["reimburse_id"] } } }, { "type": "function", "function": { "name": "query_reimbursement_by_employee", "description": "根据员工姓名查询该员工全部报销单,适用于用户询问某人全部报销情况时。", "parameters": { "type": "object", "properties": { "employee_name": { "type": "string", "description": "员工姓名" } }, "required": ["employee_name"] } } }, { "type": "function", "function": { "name": "query_approval_by_reimburse", "description": "查询指定报销单的审批记录,适用于用户询问审批进展时。", "parameters": { "type": "object", "properties": { "reimburse_id": { "type": "string", "description": "报销单编号" } }, "required": ["reimburse_id"] } } } ]

注意这里有个关键设计:函数的描述不再依赖长篇自然语言,而是结构化参数约束。模型通过description字段理解何时调用,通过parameters字段理解如何生成参数。

4.4 编写 AI Agent 消费端

现在编写model_consumer.py,演示 AI 如何消费这套业务模型。

# 文件路径:model_consumer.py import json from openai import OpenAI from business_model.tools import TOOL_REGISTRY, build_openai_tools from business_model.schema import REIMBURSEMENT_SCHEMA, APPROVAL_SCHEMA # 初始化客户端,请替换为你自己的 base_url 和 api_key client = OpenAI( base_url="https://your-llm-api.example.com/v1", api_key="your-api-key" ) SYSTEM_PROMPT = """ 你是一个企业报销助手。你可以查询报销单信息、审批记录。 在回答用户问题时,需要调用对应工具获取真实数据,不能编造。 如果工具返回错误信息,请把错误信息如实告知用户。 """ def run_agent(user_message: str): messages = [ {"role": "system", "content": SYSTEM_PROMPT}, {"role": "user", "content": user_message} ] # 把业务对象模型注入系统提示词,增强模型的业务理解 business_context = ( "### 业务对象说明\n" "报销单结构定义:\n" f"{json.dumps(REIMBURSEMENT_SCHEMA, ensure_ascii=False, indent=2)}\n" "审批单结构定义:\n" f"{json.dumps(APPROVAL_SCHEMA, ensure_ascii=False, indent=2)}\n" ) messages[0]["content"] += "\n" + business_context tools = build_openai_tools() response = client.chat.completions.create( model="your-model-name", messages=messages, tools=tools, tool_choice="auto", temperature=0 ) assistant_message = response.choices[0].message # 如果模型决定调用工具,执行工具调用 if assistant_message.tool_calls: tool_results = [] for tool_call in assistant_message.tool_calls: func_name = tool_call.function.name func_args = json.loads(tool_call.function.arguments) print(f"[Agent 调用工具] {func_name}({func_args})") func = TOOL_REGISTRY.get(func_name) if func is None: result = {"error": f"未找到工具: {func_name}"} else: result = func(**func_args) tool_results.append({ "tool_call_id": tool_call.id, "role": "tool", "name": func_name, "content": json.dumps(result, ensure_ascii=False) }) # 把工具结果追加到对话中,让模型基于真实数据进行最终回答 messages.append(assistant_message) messages.extend(tool_results) final_response = client.chat.completions.create( model="your-model-name", messages=messages, temperature=0 ) return final_response.choices[0].message.content return assistant_message.content if __name__ == "__main__": # 测试一:查询单个报销单 answer = run_agent("请帮我查一下 RB202501001 报销单的详情?") print("\n【回答一】") print(answer) print("\n" + "=" * 60 + "\n") # 测试二:查询某个员工的报销单列表 answer = run_agent("张伟提交过哪些报销单?") print("\n【回答二】") print(answer)

这段代码的核心流程是:

  1. 注入业务对象模型到系统提示词,让模型知道“报销单”长什么样。
  2. 注册可调用工具,模型根据用户问题选择工具。
  3. 模型生成结构化参数,应用层执行真实业务函数。
  4. 工具结果反馈给模型,模型基于真实数据生成自然语言回答。

4.5 初始化数据并运行

运行前先初始化数据库并插入演示数据。

# 文件路径:seed_data.py import json from business_model.db import init_db, get_connection from datetime import datetime init_db() sample_data = [ { "reimburse_id": "RB202501001", "employee_name": "张伟", "department": "技术部", "total_amount": 1280.50, "reason": "北京出差参加技术峰会", "status": "approved", "items": [ {"category": "transport", "amount": 580.00, "description": "高铁往返"}, {"category": "hotel", "amount": 520.00, "description": "住宿一晚"}, {"category": "meal", "amount": 180.50, "description": "餐饮"} ] }, { "reimburse_id": "RB202501002", "employee_name": "张伟", "department": "技术部", "total_amount": 300.00, "reason": "上海客户现场支持", "status": "submitted", "items": [ {"category": "transport", "amount": 300.00, "description": "打车费用"} ] }, { "reimburse_id": "RB202501003", "employee_name": "李娜", "department": "市场部", "total_amount": 2300.00, "reason": "广州行业展会布展", "status": "rejected", "items": [ {"category": "hotel", "amount": 1500.00, "description": "酒店两晚"}, {"category": "meal", "amount": 500.00, "description": "商务用餐"}, {"category": "other", "amount": 300.00, "description": "物料费"} ] } ] with get_connection() as conn: for item in sample_data: conn.execute( """ INSERT INTO reimbursements (reimburse_id, employee_name, department, total_amount, reason, status, items) VALUES (?, ?, ?, ?, ?, ?, ?) """, ( item["reimburse_id"], item["employee_name"], item["department"], item["total_amount"], item["reason"], item["status"], json.dumps(item["items"], ensure_ascii=False) ) ) conn.execute( """ INSERT INTO approvals (approval_id, reimburse_id, approver, decision, comment, approved_at) VALUES (?, ?, ?, ?, ?, ?) """, ( "AP202501001", "RB202501001", "王经理", "approved", "符合差旅标准,同意报销", datetime.now().isoformat() ) ) print("演示数据初始化完成")

运行命令:

python seed_data.py python model_consumer.py

预期输出流程为:

[Agent 调用工具] query_reimbursement({'reimburse_id': 'RB202501001'}) 【回答一】 已为您查询到报销单 RB202501001 的详情: - 员工:张伟(技术部) - 金额:1280.50 元 - 事由:北京出差参加技术峰会 - 状态:已通过审批 - 明细:高铁往返 580 元,住宿一晚 520 元,餐饮 180.50 元

注意,不同模型的输出措辞可能略有差异,但核心工具调用流程是一致的。

5. 常见问题与排查思路

5.1 模型没有调用工具,直接瞎编答案

现象:用户问报销单详情,模型直接生成了一段看似合理但数据库中不存在的数据。

原因

  • 函数描述不够清楚,模型不知道什么时候该调用。
  • 模型版本或接口不支持 Function Calling。
  • tool_choice设置不合理。

排查步骤

  1. 查看 API 返回的完整响应中是否包含tool_calls字段。
  2. 检查 tools 参数是否成功传入,结构是否符合 API 规范。
  3. 尝试将tool_choice设置为{"type": "function", "function": {"name": "query_reimbursement"}}强制模型调用。

解决思路

response = client.chat.completions.create( model="your-model-name", messages=messages, tools=tools, tool_choice={"type": "function", "function": {"name": "query_reimbursement"}}, temperature=0 )

5.2 工具参数生成格式错误

现象:模型生成的参数不符合 JSON Schema 要求,比如缺少必填字段或类型错误。

原因

  • 参数的description不够具体。
  • Schema 结构过于复杂,嵌套层级太深。
  • 模型本身参数生成能力有限。

解决思路

  • 简化参数结构,优先使用扁平化参数。
  • description中给出明确示例,例如“报销单编号,例如 RB202501001”。
  • 在应用层增加参数校验,不符合 Schema 时返回错误信息重新请求模型修正。
from jsonschema import validate, ValidationError def safe_call_tool(func_name, func_args): """带 Schema 校验的工具调用。""" # 这里简化处理,实际可以维护参数 Schema 映射 try: return TOOL_REGISTRY[func_name](**func_args) except ValidationError as e: return {"error": f"参数校验失败: {e.message}"}

5.3 工具返回数据太长,超出模型上下文限制

现象:查询某个员工的全部报销单,结果太多导致上下文超限或回答质量下降。

原因:工具返回数据没有做裁剪。

解决思路

  • 在工具函数内部限制返回条数。
  • 对大字段(如items)做摘要处理。
  • 分页查询,模型需要时再调用下一页。
@register_tool def query_reimbursement_by_employee(employee_name: str, limit: int = 10) -> list: """根据员工姓名查询报销单,最多返回 limit 条。""" with get_connection() as conn: rows = conn.execute( "SELECT * FROM reimbursements WHERE employee_name = ? LIMIT ?", (employee_name, limit) ).fetchall() return [dict(row) for row in rows]

5.4 业务模型更新后 AI 行为不一致

现象:业务规则变了(比如新增了报销状态),模型还是按旧状态回答。

原因:业务模型已经更新,但系统提示词中注入的业务对象说明没有同步更新。

解决思路

  • 把业务对象模型作为独立版本管理,构建时自动注入,而不是写死在代码里。
  • 每次业务模型变更后,执行回归测试。
  • 建立“业务模型 → 系统提示词 → 工具定义”的自动生成链路,减少手工维护。
问题现象常见原因解决思路
模型不调用工具函数描述不清 / 不支持 Function Calling检查 tools 参数,强制指定 tool_choice
参数格式错误Schema 复杂或描述不充分简化结构,添加示例,增加校验
返回数据超出上下文未做裁剪或分页限制返回条数,大字段摘要化
业务更新后行为不一致提示词与业务模型脱节版本化管理,自动生成提示词,回归测试

6. 最佳实践与工程建议

6.1 把业务模型当作一等公民管理

既然目标是“Model your business once”,那么这套模型就不能散落在代码各个角落。建议在工程上把它作为独立资产管理:

  • 与代码同库,采用独立的schemas/目录。
  • 编写模型的单元测试,确保 Schema 合法且与数据库结构一致。
  • 模型变更走代码评审流程,并且要有版本号。

具体到代码层面,可以增加一层“模型自检”逻辑:

# 文件路径:business_model/validate_schema.py from jsonschema import Draft7Validator from .schema import REIMBURSEMENT_SCHEMA, APPROVAL_SCHEMA def validate_reimbursement(data: dict) -> list: """校验报销单数据是否符合业务模型。""" validator = Draft7Validator(REIMBURSEMENT_SCHEMA) errors = sorted(validator.iter_errors(data), key=lambda e: e.path) return [f"{list(e.path)}: {e.message}" for e in errors]

6.2 工具函数的异常处理与日志

工具函数是 AI 触达业务系统的入口,必须有完善的异常处理。一个未被捕获的异常会导致整个对话链路失败,用户看到的只是“系统错误”。

推荐设计模式:

import functools import logging logger = logging.getLogger(__name__) def tool_handler(func): """工具函数统一异常处理装饰器。""" @functools.wraps(func) def wrapper(*args, **kwargs): try: result = func(*args, **kwargs) logger.info("Tool %s called with %s, result=%s", func.__name__, kwargs, result) return result except Exception as e: logger.exception("Tool %s failed: %s", func.__name__, e) return {"error": f"工具执行失败: {str(e)}"} return wrapper

需要注意,日志中不要记录敏感字段(如身份证号、银行卡号),生产环境更要加强日志脱敏。

6.3 权限与安全边界

给 AI 开放工具调用能力,等于开放了代码执行入口。权限控制是必须的:

最小权限原则:AI Agent 只能调用完成业务所必需的工具。查询类工具只给只读权限,不要在工具函数里写修改操作。

用户身份透传:工具调用时必须知道当前对话用户是谁。AI 层在生成参数时不应该有权限决定“以谁的身份操作”,身份应该由上层系统注入。

def query_reimbursement_by_employee(employee_name: str, current_user: str = None): # 校验 current_user 是否有查看该员工报销单的权限 if not has_permission(current_user, "reimbursement:read", employee_name): return {"error": "您没有权限查看该员工的报销单"} # 继续查询

敏感操作审批:对于创建、修改、删除类操作,建议增加人工审批环节,不要由 AI 直接一键完成。

6.4 可观测性与测试

AI 应用的调试比传统应用困难得多。必须建立可观测体系:

  • 记录每次用户输入、模型输出、工具调用参数和结果。
  • 对工具调用失败率、参数错误率进行指标监控。
  • 建立回归测试集,每次业务模型更新后自动运行。
# 文件路径:tests/test_tools.py import pytest from business_model.tools import query_reimbursement def test_query_reimbursement_exist(): result = query_reimbursement("RB202501001") assert result["employee_name"] == "张伟" def test_query_reimbursement_not_exist(): result = query_reimbursement("RB999999999") assert "error" in result

测试集的作用不只是验证函数逻辑,更重要的是验证“业务模型与提示词的一致性”。可以把典型对话场景保存为测试用例,每次模型或业务模型变更后运行,防止行为漂移。

7. 总结与学习路线

“Model your business once – for humans and AI alike” 本质上是一种架构思想的转变:把业务知识从自然语言提示词中解放出来,沉淀为结构化、可复用、可校验的业务模型。人通过界面消费这套模型,AI 通过 Function Calling 消费这套模型,两端共享同一份事实源。

本文通过一个差旅报销案例,完整演示了:

  • 使用 JSON Schema 定义业务对象模型。
  • 使用注册表模式实现可被 AI 调用的业务函数。
  • 使用 Function Calling 打通大模型与业务系统的调用链路。
  • 围绕模型、函数、权限、日志建立工程化保障。

接下来你可以继续深入的方向包括:

  • 研究 Agent 多工具编排:当一次用户请求需要调用多个业务函数时,如何设计编排策略。
  • 引入业务语义层中间件:例如把数据库表结构自动映射为业务模型的工具。
  • 探索事件驱动业务模型:当业务事件发生时,如何让 AI 实时感知并触发后续动作。
  • 建设更大的业务模型资产库:从报销这样的单业务场景,扩展到订单、库存、客户、财务等多域模型。

在实际项目中,优先关注三件事:一是业务模型的版本管理,二是工具函数的安全边界,三是建立 AI 回归测试集。这三点做到位,AI 应用才能从 Demo 走向生产环境。

如果本文对你有帮助,可以收藏备用。也欢迎在实际落地过程中多尝试不同的建模方式,找到最适合你团队业务形态的方案。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/8 12:52:50

EMD包络谱分析完整链路:从IMF筛选到滚动轴承故障诊断

简介:面向信号时频分析的EMD算法MATLAB实现,核心功能是将非线性非平稳信号逐层分解为多个IMF分量并计算残余项,适合信号处理初学者、机械故障诊断研究者以及需要做包络谱分析的工程人员。压缩包内仅含1个m源文件,大小约540B&#…

作者头像 李华
网站建设 2026/9/8 12:51:36

AI生成Verilog的模块化之道:HiVeGen分层生成实践

1. 为什么AI写的RTL总是一坨“巨石模块”先说个我自己的真实经历。去年我让某个大模型帮我写一个带Cache的简单RISC-V核心,模型确实几分钟就给我端出来一份“能看”的代码。但我打开文件一看,整整一个module,内部塞了取指、译码、执行、访存、…

作者头像 李华
网站建设 2026/9/8 12:50:43

TestComplete对象识别深度优化:从频繁失败到稳定定位

1. 为什么你的TestComplete脚本总在对象识别上翻车用TestComplete做UI自动化的人,十有八九都经历过这种场景:昨晚还跑得好好的回归脚本,今天一早起来失败率飙到80%,报错清一色是Object not found或者Window unrecognized。你第一反…

作者头像 李华
网站建设 2026/9/8 12:50:29

单片机毕设项目:基于 STM32 或 51 单片机的蜂鸣告警坐姿矫正智能台灯设计与实现 基于 STM32 或 51 单片机的蓝牙传输智能台灯人机交互系统设计

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于嵌入式单片机,Java、小程序技术领域和毕业项目实战 ✌️…

作者头像 李华
网站建设 2026/9/8 12:50:17

FPGA HDMI视频输入与环路输出实验:原理、时序与调试全解析

我之前带 FPGA 入门项目时,很多同学跑完流水灯和串口回环之后,会陷入一个"不知道下一步做什么"的空窗期。其实有个实验特别适合卡在这个节点做——HDMI 视频输入与环路输出。它不像图像算法那样依赖大量数学基础,也不像高速接口那样…

作者头像 李华
网站建设 2026/9/8 12:49:13

放大器频率补偿全解析:从自激振荡到相位裕度与Miller补偿

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华