注意:
- 本教程需要访问 Oracle Cloud。要注册免费账户,请参阅开始使用 Oracle Cloud Infrastructure 免费套餐。
- 它使用 Oracle Cloud Infrastructure 身份证明、租户和区间的示例值。完成实验室时,请将这些值替换为特定于云环境的值。
使用多代理通信协议服务器构建 AI 代理以解决发票问题
简介
处理大量产品(如分销商、行业和零售连锁店)的公司通常面临着基于不准确、不完整或多种文本描述来识别产品的挑战。在手动输入数据的环境中,输入错误、缩写和不同的贸易名称会使企业资源计划 (Enterprise Resource Planning,ERP)、客户关系管理 (Customer Relationship Management,CRM) 和电子商务平台等系统中难以正确识别项目。
在这种情况下,通常需要具有以下功能的工具:
-
解释用户提供的非正式或不正确的描述。
-
根据语义相似性建议最相似的产品。
-
如果语义搜索未找到相关结果,则保证使用传统算法(例如模糊匹配)进行回退。
-
与 API 集成,并自动执行智能代理流。
在本教程中,我们将学习如何创建专门用于解决客户退货发票中不一致的 AI 代理。座席能够与提供向量搜索和发票检索工具的 MCP 服务器进行交互,使座席能够根据客户提供的信息自动查找公司的原始应收账款发票。
MCP 服务器(模型上下文协议)是一个软件组件,负责通过标准化的消息和工具协议中介智能代理与外部服务之间的通信。它充当语言模型 (LLM) 与现有 API 之间的桥梁,允许 AI 代理访问传统系统的特定功能,而无需重新编写或直接调整这些功能。
如何工作?
MCP 服务器:
- 公开一组表示代理可以调用的操作或服务的命名工具。
- 每个工具都可以连接到数据库功能、REST API、旧系统或任何可编程操作。
- 接收代理命令(采用 JSON 格式),执行相应的服务,并返回标准化的响应。
使用旧有应用程序
传统应用通常已通过数据库、文件或内部 API 提供功能。使用 MCP Server ,您可以:
-
封装对 REST 服务、存储过程或 SQL 查询的调用。
-
使代理可以通过统一通信接口访问这些服务。
-
将旧系统与基于会话式 AI 和 RAG 的现代架构集成。
优点
-
重用现有业务逻辑。
-
无需重构旧系统。
-
使 LLM 代理能够以安全和受控的方式与外部系统进行交互。
-
促进 AI 和后端服务集成中的测试、版本控制和模块化。
此代理基于 Oracle Cloud Infrastructure (OCI) 生成式 AI 语言模型,并与由 MCP 服务器管理的动态声明的工具集成。
通过这两个组件的集成,系统可以启用基于 Oracle LLM 的代理:
- 使用 MCP 使用远程托管的工具。
- 对产品和 EAN 执行智能搜索。
- 查找对应的应收账款发票。
- 使用 Phoenix 和 OpenTelemetry 记录观测的所有内容。
这种模块化设计允许系统的可重用性和轻松演化到发票以外的领域。
目标
-
使用 LangGraph 和 LangChain 配置 AI 代理以使用结构化提示。
-
使用此代理与使用
stdio
协议的 MCP 服务器集成。 -
使用服务器上注册的远程工具可以:
- 从产品说明执行向量搜索。
- 确定货品最有可能的 EAN 代码。
- 根据客户、省/自治区/直辖市和价格等标准搜索原始发票。
-
使用 Phoenix 和 OpenTelemetry 实时监视座席执行。
-
基于 JSON 输入模拟实际的问题解决方法,例如:
{ "customer": "Customer 43", "description": "Harry Potter", "price": 139.55, "location": "RJ" }
Prerequisites
-
访问 OCI 租户以管理您的云资源。您可以通过
oracle.com/cloud/free
免费注册。 -
安装 Python
version 3.12
或更高版本。 -
在启用了 OCI Generative AI 服务的情况下访问 OCI 账户。
-
安装并配置文件 Python
Langchain
库。 -
使用 OCI Generative AI 访问
cohere.command-r-08-2024
模型。 -
安装辅助库:
oracledb
sentence_transformers
numpy
mcp-server-fastmcp
asyncio
langchain_core
langchain_community
mcp
langgraph
langchain_mcp_adapters
phoenix
(对于具有 OpenTelemetry 的可观测性)opentelemetry-sdk
,opentelemetry-exporter-otlp
-
具有以下工具的功能性 MCP 服务器:
resolve_ean
search_vectorized_product
search_invoices_by_criteria
-
配置
server_invoice_items.py
文件以作为模拟 ERP 的 MCP 服务器运行。 -
使用
pip install -r requirements.txt
命令下载并安装requirements.txt
文件。
任务 1:创建 Oracle Database 23ai(始终免费)
在本任务中,我们将学习如何在始终免费模式下预配 Oracle Database 23ai。此版本提供完全托管的环境,非常适合开发、测试和学习,且无需额外付费。
-
登录 OCI 控制台,导航到 Oracle Database 和 Autonomous Database ,然后单击创建 Autonomous Database 实例。
-
输入以下信息。
- 数据库名称:输入实例的标识名称。
- 工作量类型:根据您的需要选择数据仓库或事务处理。
- 区间:选择合适的区间来组织资源。
-
选择始终免费以确保实例是免费预配的。
-
为
ADMIN
用户创建安全密码,该密码将用于访问数据库。 -
查看设置,然后单击创建 Autonomous Database 。等待几分钟,让实例进行预配并可供使用。
任务 2:运行 Autonomous Database 表创建脚本
为我们的用例准备数据库。从此处下载并运行 SQL 脚本:script.sql
,用于为发票与 AI 代理进行对账的方案创建三个基本表(PRODUCTS
、INVOICE
和 ITEM_INVOICE
)。
-
转到 OCI 控制台,导航到 Oracle Database 和 Autonomous Database ,然后单击新创建的实例的名称。
-
单击 Database Actions(数据库操作)和 SQL 在浏览器中打开 SQL 控制台。
-
在本地下载并打开
script.sql
文件,并将所有内容粘贴到 SQL 控制台编辑器中。 -
单击 Run 或按 Ctrl + Enter 。等待确认命令已成功执行。
-
运行以下命令以验证是否已创建表。
SELECT table_name FROM user_tables;
任务 3:将示例数据插入表中
插入虚拟数据,以模拟用于应用 AI 代理的实际方案。我们将使用两个 SQL 脚本:
insert_products_books.sql
:将工作簿列表插入为产品,以及它们各自的 EAN 和说明。invoice_data_insert.sql
:插入与客户、产品和价格关联的模拟应收账款发票记录。
AI 座席将使用此数据解决退货发票中的不一致问题。
-
转到 OCI 控制台,导航到 Oracle Database 和 Autonomous Database ,然后单击新创建的实例的名称。
-
单击 Database Actions(数据库操作)和 SQL 在浏览器中打开 SQL 控制台。
-
从此处下载
insert_products_books.sql
文件内容:insert_products_books.sql
并将其粘贴到 SQL 编辑器中。 -
单击 Run 或按 Ctrl + Enter 。
-
现在,从此处下载
invoice_data_insert.sql
文件内容:invoice_data_insert.sql
文件并将其粘贴到编辑器中。 -
单击 Run 或按 Ctrl + Enter 。
-
运行以下命令以检查数据。
SELECT * FROM PRODUCTS; SELECT * FROM INVOICE; SELECT * FROM ITEM_INVOICE;
任务 4:在数据库中创建和编译高级搜索功能
创建一个名为 fn_advanced_search
的 PL/SQL 函数,用于对产品说明中的关键字执行智能搜索。AI 代理将使用此函数作为 resolve_ean
工具的一部分,允许他们根据客户在退货单上提供的说明查找最近的 EAN 代码。
该函数的作用是什么?
-
输入术语的标记化(示例:
harry poter stone
变为 [harry
,poter
,stone
]) -
具有评分的搜索技术:
-
说明中的 Direct search (直接搜索)
(LIKE '%term%')
→ +3 点。 -
使用
SOUNDEX
→ +2 点进行语音搜索。 -
使用
UTL_MATCH.EDIT_DISTANCE <= 2
→ +1 点进行类似拼写搜索。
-
-
评分逻辑:
- 每种产品的积分总和。
- 仅返回总分大于 0 的产品。
-
返回的格式:
产品作为
result_product
类型对象返回,其中包含:code
(EAN)。description
(产品说明)。similarity
(计算的搜索得分)。
执行相应步骤:
-
将完整的
similarity_search.sql
脚本复制并粘贴到自治数据库 SQL 控制台中。这包括:
- 创建
products
表(如果尚未完成)。 - 创建文本索引。
- 类型
product_result
和product_result_tab
。 fn_advanced_search
函数。- 可选测试。
- 创建
-
运行完整的脚本。结果应为
Function created
和Type created
。 -
运行以下查询以使用模拟说明测试函数。
SELECT * FROM TABLE(fn_advanced_search('harry poter askaban')) ORDER BY similarity DESC;
任务 5:使用 AI 向量化产品以进行语义搜索
在本任务中,我们将使用基于语义向量的新方法来补充基于 SQL 的高级搜索。这对于使用嵌入(短语的数字表示)来比较产品描述之间的相似性的人工智能代理尤其有用 - 比单词或语音搜索更灵活,更智能。
为此,我们将使用 Python 脚本 (process_vector_products.py
),该脚本连接到 Oracle 数据库,从 PRODUCTS
表中提取产品,将其说明转换为向量(嵌入),并使用 Oracle 数据库本身构建向量索引。
脚本的作用是什么?
- 使用
oracledb
读取products
表中的产品。 - 使用
sentence-transformers
软件包中的all-MiniLM-L6-v2
模型生成嵌入。 - 创建
embeddings_products
表以直接在 Oracle 中存储向量。 - 插入或更新记录并将向量另存为二进制 BLOB(采用序列化
float32
格式)。
注:嵌入将转换为带
np.float32.tobytes()
的字节,以存储为 BLOB。要检索向量,请使用np.frombuffer(blob, dtype=np.float32)
。
此格式允许将来的相似性搜索直接使用 SQL 或从数据库中加载向量以进行 np.dot
、cosine_similarity
操作或与 LLM 集成。
此脚本为产品生成语义嵌入,并将这些向量写入 Oracle Database 23ai。主要要点如下:
-
使用 Wallet 配置与 Oracle 的联系。
代码在 thin 模式下使用
oracledb
库,并使用 Oracle Wallet 配置安全访问。os.environ["TNS_ADMIN"] = WALLET_PATH connection = oracledb.connect( user=USERNAME, password=PASSWORD, dsn=DB_ALIAS, ... )
-
产品表的咨询。
products
表包含原始数据(ID、代码和说明)。这些描述用作生成语义向量的基础。cursor.execute("SELECT id, code, description FROM products")
-
使用
sentence-transformers
生成嵌入all-MiniLM-L6-v2
模型用于将产品说明转换为高维数字向量。model = SentenceTransformer('all-MiniLM-L6-v2') embeddings = model.encode(descriptions, convert_to_numpy=True)
-
创建嵌入表(如果不存在)。
embeddings_products
表是使用以下字段动态创建的:id
:产品标识符(主键)。code
:产品代码。description
:原始说明。vector
:包含float32
中序列化的向量的 BLOB。
CREATE TABLE embeddings_products ( id NUMBER PRIMARY KEY, code VARCHAR2(100), description VARCHAR2(4000), BLOB vector )
注:创建过程在
BEGIN...EXCEPTION
内使用EXECUTE IMMEDIATE
,以避免表已存在时发生错误。 -
使用
MERGE
插入或更新。对于每个产品,向量将转换为字节 (
float32
),并使用MERGE INTO
插入或更新到embeddings_products
表中。vector_bytes = vector.astype(np.float32).tobytes()
MERGE INTO embeddings_products ...
运行以下脚本:
注:您需要下载并配置 Oracle Wallet。
在最终机中运行该命令。
python process_vector_products.py
结束了!数据库中的产品已向量化。
为什么这很重要?
矢量搜索对于寻找产品非常有效,即使描述是主观,不精确或自然语言。
了解代码:使用 MCP 服务器的 LLM 代理
此项目由 3 个主要组件组成:
- ReAct Agent with LangGraph and OCI LLM (
main.py
)。 - 具有发票解决工具的 MCP 服务器 (
server_invoice_items.py
)。 - 使用 OCI Generative AI 和 FAISS 搜索类似产品 (
product_search.py
)。
了解每个组件的功能,并详细突出显示代码的最重要部分。
-
ReAct 使用 OCI 中的 LangGraph 和 LLM 的代理:
此组件运行主应用程序,用户可基于 Oracle Cloud 大语言模型 (LLM) 与代理进行交互。它使用
stdio
协议与 MCP 服务器通信。主要特性:
-
Phoenix 和 OpenTelemetry 的遥测配置
px.launch_app() ... trace.set_tracer_provider(provider)
-
使用
ChatOCIGenAI
创建 LLM 模型。llm = ChatOCIGenAI( model_id="cohere.command-r-08-2024", ... )
-
用于调节发票的任务导向提示的定义。
prompt = ChatPromptTemplate.from_messages([ ("system", """You are an agent responsible for resolving inconsistencies in invoices...""), ("placeholder", "{messages}") ])
-
Local MCP Server Execution using
stdio
(使用本地 MCP 服务器执行)。# Run the client with the MCP server async def main(): async with MultiServerMCPClient( { "InvoiceItemResolver": { "command": "python", "args": ["server_invoice_items.py"], "transport": "stdio", }, } ) as client:
-
Main User Interaction Loop(主用户交互循环)。
while True: query = input("You: ") ... result = await agent_executor.ainvoke({"messages": memory_state.messages})
-
Integration with Tools Exposed by the MCP Server 。
agent_executor = create_react_agent( model=llm, tools=tools, prompt=prompt, )
-
Multiples MCP Servers 。
如果要使用多个 MCP 服务器,请在此处包括以下服务器:
# Run the client with the MCP server async def main(): async with MultiServerMCPClient( { "InvoiceItemResolver": { "command": "python", "args": ["server_invoice_items.py"], "transport": "stdio", }, "InvoiceItemResolver": { "command": "python", "args": ["another_mcp_server.py"], "transport": "stdio", }, ... } ) as client: tools = client.get_tools() if not tools: print("❌ No MCP tools were loaded. Please check if the server is running.") return
提示:
提示对于为 AI 代理建立流程和操作规则至关重要。
-
-
具有解析工具的 MCP 服务器:
此服务器通过提供工具来访问 Oracle Database 并提供产品和发票信息,从而响应座席呼叫。
主要特性:
-
Initialization the MCP Server with the Name
InvoiceItemResolver
。mcp = FastMCP("InvoiceItemResolver")
-
使用 Oracle Wallet 与 Oracle Database 连接。
connection = oracledb.connect( user=USERNAME, password=PASSWORD, dsn=DB_ALIAS, wallet_location=WALLET_PATH, ... )
-
MCP 工具的实施。
-
search_vectorized_product
:搜索具有嵌入的类似产品。
@mcp.tool() def search_vectorized_product(description: str) -> dict: """ Searches for a product by description using embeddings. """ return sercher.search_similar_products(description)
-
resolve_ean
:根据描述相似性解析 EAN。
@mcp.tool() def resolve_ean(description: str) -> dict: result = execute_search_ean(description) ... return {"ean": result[0]["code"], ...}
-
search_invoices_by_criteria
:根据多个筛选器搜索应收账款发票。
@mcp.tool() def search_invoices_by_criteria(customer: str = None, state: str = None, price: float = None, ean: str = None, margin: float = 0.05) -> list: """ Searches for outbound invoices based on customer, state, EAN, and approximate price. Allows one or more fields to be omitted. As long as an EAN has not been established, it is not useful to use this service. """ query = """ SELECT nf.no_invoice, nf.name_customer, nf.state, nf.date_print, inf.no_item, inf.code_ean, inf.description_product, inf.value_unitary FROM invoice nf JOIN item_invoice inf ON nf.no_invoice = inf.no_invoice WHERE 1=1 """ params = {} #if customer: query += " AND LOWER(nf.name_customer) LIKE LOWER(:customer)" params["customer"] = f"%{customer}%" #if state: query += " AND LOWER(nf.state) = LOWER(:state)" params["state"] = state #if ean: query += " AND inf.code_ean = :ean" params["ean"] = ean if price is not None: query += " AND inf.value_unitary BETWEEN :price_min AND :price_max" params["price_min"] = price * (1 - margin) params["price_max"] = price * (1 + margin) result = execute_query(query, params) return [ dict(zip( ["no_invoice", "name_customer", "state", "date_print", "no_item", "code_ean", "description_product", "value_unitary"], row )) for row in result ]
-
-
在
stdio
模式下运行服务器。if __name__ == "__main__": mcp.run(transport="stdio")
-
-
使用 OCI Generative AI 和 Vector Database 搜索类似产品:
此模块
product_search.py
实现了一个 Python 类,允许您从文本描述中搜索语义相似的产品,使用:- 嵌入 OCI Generative AI 。
- 使用 Oracle Database 23ai 进行向量索引。
- 与 RapidFuzz 作为回退的模糊比较。
任务 6:在 MCP 代理中配置模型和嵌入
让我们使用 OCI Generative AI 服务配置基于 MCP 协议的会话代理使用的语言模型和嵌入。
-
配置语言模型 (LLM)。
语言模型负责解释消息,生成响应并充当代理的主要大脑。
-
在
main.py
文件中进行配置。from langchain_community.chat_models.oci_generative_ai import ChatOCIGenAI llm = ChatOCIGenAI( model_id="cohere.command-r-08-2024", service_endpoint="https://inference.generativeai.us-chicago-1.oci.oraclecloud.com", compartment_id="ocid1.compartment.oc1..aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", auth_profile="DEFAULT", model_kwargs={"temperature": 0.1, "top_p": 0.75, "max_tokens": 2000} )
Parameter (参数) 说明 model_id
生成式 AI 模型 ID,例如 cohere.command-r-08-2024
service_endpoint
生成式 AI 服务区域端点 compartment_id
OCI 区间的 OCID auth_profile
文件 ~/.oci/config
中配置的配置文件的名称model_kwargs
温度、顶部 p 和响应大小 -
列出可用模型。
-
使用 OCI CLI:
oci generative-ai model list --compartment-id <seu_compartment_id>
-
使用 Python SDK:
from oci.generative_ai import GenerativeAiClient from oci.config import from_file config = from_file(profile_name="DEFAULT") client = GenerativeAiClient(config) models = client.list_models(compartment_id=config["compartment_id"]) for model in models.data: print(model.display_name, model.model_id)
-
-
-
配置用于语义搜索的嵌入。
搜索类似产品或上下文信息取决于向量嵌入。
在代理中使用的示例:
@mcp.tool() def search_vectorized_product(description: str) -> dict: """ Searches for a product by description using embeddings. """ return sercher.search_similar_products(description)
更改参数 (
product_search.py
),如下所示:class SimilarProductSearch: def __init__( self, top_k=5, minimum_distance=1.0, model_id="cohere.embed-english-light-v3.0", service_endpoint="https://inference.generativeai.us-chicago-1.oci.oraclecloud.com", compartment_id="ocid1.compartment.oc1..aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", auth_profile="DEFAULT", wallet_path="/WALLET_PATH/Wallet_oradb23ai", db_alias="oradb23ai_high", username="USER", password="Password" ):
Parameter (参数) 说明 top_k
返回的建议数。 minimum_distance
考虑相关结果的最大距离。 model_id
OCI 中嵌入模型的 ID(例如 cohere.embed-english-light-v3.0
)。service_endpoint
OCI Generative AI 区域端点。 compartment_id
区间 OCID。 auth_profile
~/.oci/config
文件中的配置文件名称。wallet_path
Oracle Database 23ai wallet 的路径。 db_alias
数据库别名, username
数据库用户。 password
数据库口令。 配置 MCP 服务器:
就像执行
process_vector_products.py
代码时所做的那样,您需要为 Oracle Database 23ai 数据库配置 Oracle Wallet。根据您的设置修改参数:
import os # Oracle Wallet settings WALLET_PATH = "/path/to/Wallet" DB_ALIAS = "oradb23ai_high" USERNAME = "admin" PASSWORD = "..." # Define the environment variable required for the Oracle client os.environ["TNS_ADMIN"] = WALLET_PATH
然后执行
process_vector_products.py
,将产品向量化到 Oracle Database 23ai 中。python process_vector_products.py
因此,LLM 模型和嵌入可供 MCP 代理使用 LangGraph 和 LangChain。
任务 7:测试产品和发票说明搜索
-
使用以下命令运行
main.py
文件。python main.py
-
当出现 You: 提示时,输入以下语句。
{ "customer": "Customer 108", "description": "Harry Poter askaban", "price": 82.26, "location": "SP"}
注:工作簿 Harry Potter 和 Azkaban 的名称拼写错误,但引擎可以毫无问题地找到它。
请注意,服务已执行:
fetch_vectorized_product resolve_ean search_invoices_by_criteria
-
现在,输入以下语句。
{ "customer": "Customer 108", "description": "Harry Poter askaban", "price": 82.26}
您将看到未找到发票记录。这是因为地点是查找发票的关键。
-
现在,输入以下语句。
{ "customer": "Customer 108", "description": "Harry Poter", "location": "SP"}
这一次,我们输入了地点,但省略了单价。
但已找到发票。这是因为价格不是基本的,但它确实有助于缩小差距,使其更加自信。
测试的一些示例包括:
{ "customer": "Customer 108", "description": "Harry Poter askaban", "price": 82.26, "location": "SP"} { "customer": "Customer 108", "description": "Harry Poter askaban", "price": 82.26} { "customer": "Customer 108", "description": "Harry Poter askaban", "location": "SP"} { "customer": "Customer 108", "description": "Harry Poter askaban", "price": 82.26, "location": "RJ"} { "customer": "Customer 125", "description": "Harry Potter Chamber", "price": 79.16, "location": "SP"} { "customer": "Customer 125", "description": "Harry Potter Chamber", "price": 79.15, "location": "SP"}
任务 8:查看凤凰城的可观测性
在浏览器中输入 http://localhost:6006/
以查看凤凰城的可观测性。
相关链接
确认
- 作者 - Cristiano Hoshikawa(Oracle LAD A-Team 解决方案工程师)
更多学习资源
通过 docs.oracle.com/learn 浏览其他实验室,或者通过 Oracle Learning YouTube 频道访问更多免费学习内容。此外,请访问 education.oracle.com/learning-explorer 以成为 Oracle Learning Explorer。
有关产品文档,请访问 Oracle 帮助中心。
Build an AI Agent with Multi-Agent Communication Protocol Server for Invoice Resolution
G35147-06
Copyright ©2025, Oracle and/or its affiliates.