内容
# 公司智商
公司智商是一种基于 Teams 的编排代理,它了解公司。它通过路由到工具来回答问题:一个 SQL 数据工具(最高优先级)、文档搜索(Azure AI 搜索)、Microsoft Graph 工具(SharePoint、OneDrive、通过用户单点登录的电子邮件)和网络搜索。UC-01(SBS AI 查询)是参考用例。它是基于 M365 代理工具包“与您的数据聊天(Azure AI 搜索)”模板,使用 Teams AI 库 v2(`@microsoft/teams.*` v2,普通 Node.js CommonJS)构建。
## 架构
```
Teams 消息
→ src/index.js(启动:Key Vault 机密解析,然后应用启动)
→ src/app/app.js(应用设置、单点登录登录流程、对话历史)
src/auth/userContext.js(来自单点登录令牌的身份 → 通过 USER_SCOPE_MAP 的数据范围)
→ src/orchestrator/orchestrator.js(带有函数调用和审计日志的 ChatPrompt)
→ src/tools/queryCompanyData.js (意图白名单 → 验证器 → 参数化 SQL,行级范围)
→ src/tools/searchDocuments.js (Azure AI 搜索混合检索)
→ src/tools/searchSharePoint.js (Graph 搜索 API,委托令牌)
→ src/tools/searchOneDrive.js (Graph /me/drive 搜索,委托令牌)
→ src/tools/searchEmail.js (Graph /me/messages $search,委托令牌)
→ src/tools/getCalendar.js (Graph /me/calendarView,委托令牌)
→ src/tools/getPlannerTasks.js (Graph /me/planner/tasks,委托令牌)
→ src/tools/findPeople.js (Graph /me/people 模糊查找,委托令牌)
→ src/tools/webSearch.js (标志门控允许列表获取;Bing Grounding 稍后)
→ src/connectors/* (外部:ask_agent_<name> 通过 Foundry Responses API
或 HTTP 合同;mcp_<server>_<tool> 通过 MCP
Streamable HTTP — 不受信任,断路, 无令牌)
→ src/formatting/responseFormatter.js(自适应卡片表格,引用,标记外部部分)
→ 消息活动返回 Teams
```
斜杠命令(在编排器之前在 `src/app/commands.js` 中解析):`/help`、`/whoami`、`/data`、`/docs`、`/mail`、`/calendar`、`/agents`、`/web`。未知命令获取帮助文本,从不 AF-1。
支持模块:`src/data/db.js`(mssql 池)、`src/data/intents.js`(应用中唯一的 SQL)、`src/auth/graph.js`(委托 Graph 获取)、`src/auth/azureCredential.js`(托管身份身份验证)、`src/secrets.js`(启动时的 Key Vault)。
硬规则:
- AI 永远不会生成或执行 SQL。模型只选择一个允许的意图并通过函数调用填充参数;所有 SQL 都在应用程序代码中参数化(`src/data/intents.js`)。
- 每个 SQL 执行都带有行级范围谓词 `ri.retailer_id = @userScope`。范围来自通过 `USER_SCOPE_MAP` 的已登录用户;如果未映射的已登录用户,则会得到“未分配数据范围”(从不回退)。`DEV_USER_SCOPE` 仅在无人登录时应用(游乐场)。
- Graph 工具仅使用委托令牌(Teams 单点登录 → OAuth 连接令牌交换)。结果继承已登录用户的权限。永远不是仅应用。
- 未知或无法解析的请求会得到 AF-1 回退响应;机器人永远不会猜测意图。
- 机密存储在 `env/.env.*.user` 本地和 Key Vault(在启动时通过托管身份解析)中 — 永远不会在代码或提交的环境文件中。
- 公共网络工具仅在 `CONNECTOR_PUBLIC_WEB_ENABLED=true` 时注册,仅获取 `ORG_WEBSITE_ALLOWLIST` 域,其输出在标记为外部信息的单独部分中渲染。
## 环境变量
| 变量 | 目的 | 本地源 | Azure 源 |
| - | - | - | - |
| `AZURE_OPENAI_API_KEY` | Azure OpenAI 密钥(省略以使用托管身份) | `env/.env.*.user` | Key Vault `azure-openai-api-key` |
| `AZURE_OPENAI_ENDPOINT` / `AZURE_OPENAI_API_VERSION` | Azure OpenAI 资源 | 环境文件 | 应用设置 |
| `AZURE_OPENAI_CHAT_DEPLOYMENT` / `AZURE_OPENAI_EMBEDDING_DEPLOYMENT` | 部署 | 环境文件 | 应用设置 |
| `AZURE_SEARCH_ENDPOINT` / `AZURE_SEARCH_INDEX_NAME` | AI 搜索资源 + 索引 | 环境文件 | 应用设置 |
| `AZURE_SEARCH_QUERY_KEY` | 运行时搜索密钥(省略托管身份) | 环境文件 | Key Vault `azure-search-query-key` |
| `AZURE_SEARCH_ADMIN_KEY` | 索引器脚本专用 | 环境文件 | — |
| `AZURE_SQL_SERVER` / `AZURE_SQL_DATABASE` | SQL 目标 | 环境文件 | 应用设置 |
| `AZURE_SQL_USERNAME` / `AZURE_SQL_PASSWORD` | SQL 身份验证 — **最小特权** 应用登录(仅 `SELECT` on `sbs_test`;参见 [least-privilege-setup.sql](src/data/least-privilege-setup.sql)) | 环境文件 | Key Vault `azure-sql-username` / `azure-sql-password` |
| `AZURE_SQL_ADMIN_USERNAME` / `AZURE_SQL_ADMIN_PASSWORD` | 提升凭证,仅由 `db:seed` / `db:introspect` 使用。机器人从不使用它。 | 环境文件 | — |
| `DEV_USER_SCOPE` | 临时范围(未登录时) | 环境文件 | —(在 Azure 中未设置) |
| `USER_SCOPE_MAP` | JSON UPN/objectId → 范围 | 环境文件 | 应用设置 |
| `OAUTH_CONNECTION_NAME` | 机器人 OAuth 连接(默认 `graph`) | 环境文件 | 应用设置 |
| `SHAREPOINT_SITES` | 以逗号分隔的站点 URL,限制 SharePoint 搜索 | 环境文件 | 应用设置 |
| `CONNECTOR_PUBLIC_WEB_ENABLED` / `ORG_WEBSITE_ALLOWLIST` | 网络工具门控 + 域 | 环境文件 | 应用设置 |
| `MCP_SERVERS` | JSON:`[{name,url,authHeader?,authMode?:"user",connection?,allowedTools?,allowedContext?}]` | 环境文件 | 应用设置 |
| `FOUNDRY_AGENTS` | JSON:`[{name,description,projectEndpoint,agentIdOrName,identity?:"user"\|"app",allowedContext?}]` | 环境文件 | 应用设置 |
| `HTTP_AGENTS` | JSON:`[{name,description,url,tokenEnv,allowedContext?}]` | 环境文件 | 应用设置 |
| `FABRIC_DATA_AGENTS` | JSON:`[{name,description,workspaceId,dataAgentId}]` — 注册 `ask_fabric_<name>` | 环境文件 | 应用设置 |
| `FABRIC_SQL_ENDPOINT` / `FABRIC_DATABASE` | 湖屋 SQL 分析端点和数据库。两者皆需,否则源未注册( `/sources` 会显示)。 | 环境文件 | 应用设置 |
| `FABRIC_LOCAL_DEV_IDENTITY` | **仅限本地。** 当没有 Teams 单点登录(游乐场/托管)时,使用开发者的自己的 `az login` 身份用于 Fabric。**在 Azure 上硬禁用** — 否则 `DefaultAzureCredential` 将返回托管身份并悄悄地将其变为应用身份源。 | 环境文件 | 从未设置 |
| `FABRIC_TENANT_ID` / `FABRIC_CLIENT_ID` / `FABRIC_CLIENT_SECRET` | **运行时未使用。** Fabric 源作为已登录用户进行身份验证;不涉及服务主体。仅为参考/工具保留。 | 环境文件 | — |
| `GRAPH_SCOPES` | 委托范围列表(必须与 OAuth 连接匹配) | 环境文件 | — |
| `KEY_VAULT_URI` | 启用启动机密解析 | — | Bicep 输出 |
| `CLIENT_ID` / `CLIENT_SECRET` / `TENANT_ID` / `BOT_TYPE` | 机器人身份 | `.localConfigs`(生成) | Bicep(托管身份) |
## 如何添加新的 SQL 意图
1. 在 [src/data/intents.js](src/data/intents.js) 中为 `INTENTS` 添加一个条目:参数规则(`required`、`maxLength`、`pattern`,可选 `normalize`、`sqlType`)和参数化的 `where` 片段。永远不要插入值 — 将所有内容绑定为 `@params`。范围谓词由 `buildStatement()` 自动注入。
2. 将意图名称添加到其他内容中 — 工具的枚举读取 `Object.keys(INTENTS)`。
3. 在 [src/data/intents.test.js](src/data/intents.test.js) 中添加验证器/语句测试(范围谓词测试循环遍历所有意图)。
4. 如果意图需要新列,请扩展 `BASE_SELECT` 和格式化器的 `TABLE_COLUMNS`。
## 如何添加新工具
1. 创建 `src/tools/<name>.js` 导出 `{ name, description, parameters (JSON schema), handler(args, context) }`。处理程序返回一个 JSON 可序列化结果;返回 `{ error: "..." }` 形状以表示结构化拒绝(`auth_required` 触发登录流程;`validation_failed` 映射到 AF-1)。
2. 在 [src/tools/index.js](src/tools/index.js) 中注册它(如果必须默认不可见,则使用配置标志)。
3. 教模型何时使用它:在 [src/app/instructions.txt](src/app/instructions.txt) 中添加选择规则。
4. 如果它生成新的渲染形状,请扩展 [src/formatting/responseFormatter.js](src/formatting/responseFormatter.js)。
5. 通过现有的 JSON 行审计事件记录日志(日志中不包含用户内容)。
## 数据源和身份
公司智商在 **一个** 工具(`queryCompanyData`)后面有两个结构化数据源。模型从目录中选择一个源;它永远不会编写 SQL。每个源在其代码中声明其 **范围策略** — 没有声明策略的源将在 **启动时** 失败,而不是在查询时静默失败。
| 源 | 数据 | 身份 | 如何强制执行行级访问 |
| - | - | - | - |
| `company_sql`(Azure SQL,`sbs_test`) | 公司产品、供应商、商品 | 应用登录,**最小特权**(仅 `SELECT` on `sbs_test`) | **`row_predicate`** — 编译器将 `ri.retailer_id = @userScope` 注入到 **每个** 语句(普通、连接、聚合、分组)。强制且无条件;在测试中声明。 |
| `healthcare_fabric`(Fabric 湖屋 SQL 分析端点) | 患者、提供者、遭遇、预约、实验室、笔记 | **已登录用户**(委托令牌) | **`enforced_by_source`** — TDS 连接携带用户的令牌,因此 **Fabric 在引擎内部强制执行用户的权限**。他们看到他们有权看到的内容。 |
**Fabric 源以用户身份运行,而不是以服务主体身份运行。** 一个实验表明,Fabric SQL 分析端点通过 TDS 接受委托的用户令牌,因此不会暴露组织范围的数据,也不会在运行时出现客户端密钥。有两件事依赖于此:
- **TDS 受众是 `https://database.windows.net/`** — *不是* `https://api.fabric.microsoft.com/`,TDS 拒绝该受众(该受众仅用于 Fabric REST / data-agent MCP 接口)。这就是为什么有两个 Fabric OAuth 连接:`fabric`(REST/MCP)和 `fabric_sql`(TDS)。
- **`encrypt: true` + `trustServerCertificate: false` 是强制性的。** 省略它们会导致 Entra 握手失败,并表现为登录超时,看起来与错误密码完全相同。
其他艰难的细节:`18456` 登录失败 *在* 成功获取令牌后意味着 Fabric 端缺少授权(租户设置“服务主体可以调用 Fabric 公共 API”,以及工作区/项目授予) — **不是** 凭证错误,因此不要追踪机密。冷的湖屋端点在首次连接时很慢,因此源在启动时预热,实际查询重试,但 `probe()` 快速失败(单次尝试,~10 秒),因此一个死亡源永远不会阻塞用户的回合。
**如果源曾经切换到应用身份**,其范围策略必须重新审视:每个用户都将看到相同的数据,并且必须在每个响应中标记。格式化器 — 而不是模型 — 在每个卡片上发出源标签,因此不能省略。
不支持跨源连接:单个查询只能引用一个源的表。跨多个源的问题会生成两个工具调用,在文本中组合。目录是检查的工件(`src/data/catalogs/`);运行时永远不会自动发现架构。在湖屋更改时重新运行 `npm run fabric:introspect`,然后审查差异。
## 身份架构 — 一个公司智商单点登录应用,一个 URI/机器人
Teams **机器人** 单点登录需要令牌交换资源 URI 嵌入机器人的 ID(`api://botid-<botId>`)— 客户端拒绝任何其他形状的 `resourcematchfailed`。因此,一个公司智商拥有的 Entra 应用携带 **每个环境机器人一个 `api://botid-…` 标识符 URI**(因为它是 v2 令牌应用;租户策略阻止 v1 应用上的此类 URI,从而排除重用共享的 Mela 应用进行单点登录)。
| 应用 | 角色 | 引用位置 |
| - | - | - |
| **CompanyIQlocal** (`4a91eb47…` = `SSO_APP_ID` everywhere, and local `BOT_ID`) | 公司智商单点登录应用:`access_as_user`, Teams 客户端预授权,8 个委托 `.Read` 范围上的管理员同意,标识符 URI `api://botid-<local bot>` **和** `api://botid-<dev bot>`。本地,它兼作机器人通道凭证。 | `webApplicationInfo.id`; OAuth 连接 `graph`(客户端 ID + `companyiq-oauth` 秘密)在两个机器人注册中 |
| **Mela AI Meeting Assistant** (`7ed650f2…` = `AZURE_CLIENT_ID`) | 应用凭证,用于其他集成;**不用于用户单点登录** | 仅限环境变量 |
| **bot<suffix> 托管身份** (dev) | 部署的机器人通道凭证 | Bicep (`msaAppType: UserAssignedMSI`) |
`webApplicationInfo.resource` = `api://botid-${{BOT_ID}}`(按环境解析);每个连接的令牌交换 URL 匹配其自己的机器人的 URI。添加环境 = 添加一个 `api://botid-<newBotId>` URI 到单点登录应用。
## 身份传播委托(Fabric + Foundry 作为用户)
机器人持有每个下游受众的 OAuth 连接 — `graph`(默认)、`fabric`(`https://api.fabric.microsoft.com/.default`)、`foundry`(`https://ai.azure.com/.default`)— 所有这些都交换相同的 Teams 单点登录断言。工具在调用时解析每个受众的用户令牌(`context.getAudienceToken(connection)`);缺少令牌会触发该特定连接的登录流程,并在登录后重试问题。
- **Fabric 数据代理** (`FABRIC_DATA_AGENTS` → `ask_fabric_<name>`): 调用发布的数据代理的 MCP 端点,带有用户的 **Fabric 令牌**,因此工作区/代理权限绑定到提问者。单点登录应用上的同意:Power BI 服务委托 `Item.Execute.All` + `Workspace.Read.All`。
- **具有 `identity: "user"` 的 Foundry 代理**:响应 API 调用携带用户的 `ai.azure.com` 令牌(同意:Microsoft Cognitive Services 委托 `user_impersonation`);用户需要 Foundry 项目上的 **Azure AI 用户** 角色。`identity: "app"`(默认)保留机器人的凭证。
- **硬规则(已测试)**:用户身份工具永远不会回退到应用凭证。401/403 显示为干净的“您无权访问”消息 — 这是权限模型正在运行,而不是错误 — 并且模型被指示在不重试或从另一个源回答的情况下中继它。
## 本地与部署
| | 本地/游乐场 | Azure(开发) |
| - | - | - |
| 启动 | F5 “在 Microsoft 365 代理游乐场中调试” (无身份验证)或“本地启动代理”(Teams + 开发隧道) | `atk provision --env dev` + `atk deploy --env dev` |
| 机器人身份 | Entra 应用 + 秘密(`aadApp/create`) | 用户分配的托管身份 |
| 秘密 | `env/.env.*.user` → `.localConfigs` | 通过托管身份的 Key Vault |
| 单点登录/Graph | 仅在 Teams 本地调试时有效(开发的 dev.botframework.com 注册上的 OAuth 连接) | Azure Bot 资源上的 OAuth 连接 |
| SQL 范围 | `DEV_USER_SCOPE`(游乐场)/ `USER_SCOPE_MAP`(Teams) | `USER_SCOPE_MAP` |
| 测试 | `npm test`(54 个测试,DB 模拟) | — |
| 搜索索引 | `npm run indexer:create` / `db:seed` 用于 SQL 测试模式 | 相同的资源 |
## 阶段计划
| 阶段 | 范围 | 状态 |
| - | - | - |
| 0 | 仓库卫生:声明传递依赖,修复历史积累,文件夹脚手架 | 完成 |
| 1 | 带有函数调用的编排器,工具注册,`searchDocuments` + `queryCompanyData` 存根,响应格式化器 | 完成 |
| 2 | 真实的 SQL 工具:`mssql` 池,模式内省,意图白名单,验证,行上限,审计日志,单元测试 | 完成 |
| 3 | Teams 单点登录(Entra 应用,`webApplicationInfo`,OAuth 连接)和 Graph 工具:SharePoint,OneDrive,电子邮件 | 完成(实时测试) |
| 4 | 网络搜索,Key Vault,托管身份身份验证到 Azure 服务,遥测,Azure 部署 | 进行中 |
---
# 使用 Azure AI 搜索的“与您的数据聊天”(使用 Azure AI 搜索)模板概述
该应用模板展示了如何构建最强大的 LLM 启用问答(Q&A)聊天机器人,可以直接在 Microsoft Teams 中回答有关特定源信息的问题。
该应用模板还演示了诸如以下技术的用法:
- [检索增强生成](https://python.langchain.com/docs/use_cases/question_answering/#what-is-rag) 或 RAG。
- [Azure AI 搜索](https://learn.microsoft.com/azure/search/search-what-is-azure-search)
- [Microsoft Teams SDK](https://aka.ms/teams-ai-library-v2)
## 开始使用模板
> **前提条件**
>
> 要在本地开发机器上运行模板,您需要:
>
> - [Node.js](https://nodejs.org/),支持版本:22(Node 20 已于 2026 年 4 月达到生命周期终点)
> - [Microsoft 365 智能工具包 Visual Studio Code 扩展](https://aka.ms/teams-toolkit) 版本 5.0.0 及更高版本 或 [Microsoft 365 智能工具包 CLI](https://aka.ms/teamsfx-toolkit-cli)
> - 准备您自己的 [Azure OpenAI](https://aka.ms/oai/access) 资源和 [Azure AI 搜索](https://azure.microsoft.com/en-us/products/ai-services/ai-search)。
> 要使用 Microsoft 365 智能工具包 CLI 进行本地调试,您需要执行一些额外的步骤,如 [设置用于本地调试的 Microsoft 365 智能工具包 CLI](https://aka.ms/teamsfx-cli-debugging) 中所述。
1. 首先,在 VS Code 工具栏左侧选择 Microsoft 365 智能工具包图标。
1. 在文件 *env/.env.playground.user* 中,填写您的 Azure OpenAI 密钥 `AZURE_OPENAI_API_KEY=<您的密钥>`,端点 `AZURE_OPENAI_ENDPOINT=<您的端点>`,API 版本 `AZURE_OPENAI_API_VERSION=<API 版本>`,聊天部署 `AZURE_OPENAI_CHAT_DEPLOYMENT=<您的部署>`,和嵌入部署 `AZURE_OPENAI_EMBEDDING_DEPLOYMENT=<您的嵌入部署>`。并填写您的 Azure AI 搜索端点 `AZURE_SEARCH_ENDPOINT=<您的 AI 搜索端点>`,查询密钥 `AZURE_SEARCH_QUERY_KEY=<查询密钥>`,管理员密钥 `AZURE_SEARCH_ADMIN_KEY=<管理员密钥>`(仅限索引器),和索引名称 `AZURE_SEARCH_INDEX_NAME=<索引名称>`。
1. 执行 `npm install` 和 `npm run indexer:create` 以创建文档索引(从环境文件中读取密钥;索引向量维度将根据您的嵌入模型自动推导)。一旦您使用完示例,最好删除索引。您可以使用 `npm run indexer:delete` 命令删除索引。
1. 按 F5 开始调试,这将使用 Web 浏览器在 Microsoft 365 智能工具包游乐场中启动您的应用程序。选择 `在 Microsoft 365 智能工具包游乐场中调试`。
1. 您可以发送任何消息以获取代理的响应。
**恭喜**!您现在正在运行一个可以与 Microsoft 365 智能工具包游乐场中的用户交互的应用程序:

## 模板中包含的内容
| 文件夹 | 内容 |
| - | - |
| `.vscode` | 用于调试的 VSCode 文件 |
| `appPackage` | 应用程序清单的模板 |
| `env` | 环境文件 |
| `infra` | 用于预配 Azure 资源的模板 |
| `src` | 应用程序的源代码 |
以下文件可以自定义,并演示了一个示例实现,以帮助您入门。
| 文件 | 内容 |
| - | - |
|`src/index.js`| 应用程序入口点。|
|`src/config.js`| 定义环境变量。|
|`src/app/app.js`| 主要应用程序代码|
|`src/app/azureAISearchDataSource.js`| 定义 Azure AI 搜索数据源。|
|`src/indexers/data/*.md`| 原始文本数据源。|
|`src/indexers/utils.js`| 基本索引工具。 |
|`src/indexers/setup.js`| 创建索引和上传文档的脚本。 |
|`src/indexers/delete.js`| 删除索引和文档的脚本。 |
以下是 Microsoft 365 智能工具包特有的项目文件。您可以 [访问 GitHub 上的完整指南](https://github.com/OfficeDev/TeamsFx/wiki/Teams-Toolkit-Visual-Studio-Code-v5-Guide#overview) 以了解 Microsoft 365 智能工具包的工作原理。
| 文件 | 内容 |
| - | - |
|`m365agents.yml`|这是主要的 Microsoft 365 智能工具包项目文件。项目文件定义了两件主要事情:属性和配置 阶段定义。 |
|`m365agents.local.yml`|使用启用本地执行和调试的操作覆盖 `m365agents.yml`。|
|`m365agents.playground.yml`| 使用启用本地执行和调试在 Microsoft 365 智能工具包游乐场的操作覆盖 `m365agents.yml`。|
## 扩展模板
要使用更多 AI 功能扩展基本 AI 聊天机器人模板,请探索 [Microsoft Teams SDK 文档](https://aka.ms/m365-agents-toolkit/teams-agent-extend-ai)。
## 附加信息和参考
- [Microsoft 365 智能工具包文档](https://docs.microsoft.com/microsoftteams/platform/toolkit/teams-toolkit-fundamentals)
- [Microsoft 365 智能工具包 CLI](https://aka.ms/teamsfx-toolkit-cli)
- [Microsoft 365 智能工具包示例](https://github.com/OfficeDev/TeamsFx-Samples)
MCP 配置
以下是此 MCP Server 的配置信息,可直接复制到 Cursor 或其他 MCP 客户端中使用。
mcp.json
连接信息
猜你喜欢
暂无推荐服务器