Planning Phase 17 - huqianghui/AI-Coach-vibe-coding GitHub Wiki

Phase 17: Agent Knowledge Base Foundry Iq

Auto-generated from .planning/phases/17-agent-knowledge-base-foundry-iq
Last synced: 2026-04-28

Context & Decisions

Phase 17 Context — Agent Knowledge Base (Foundry IQ Integration)

Phase Goal

HCP Agent 知识库管理,对齐 Azure AI Foundry Knowledge 配置体验。Admin 可在 HCP 编辑器中连接 Azure AI Search 资源的 Knowledge Base (Foundry IQ),将知识库绑定到 HCP Agent。Agent 在对话中自动使用 RAG 检索知识。

Decisions

D-01: Knowledge Base 接入方式 — MCPTool (Foundry IQ)

Decision: 使用 MCPTool(MCP 协议)连接 AI Search Knowledge Base,对齐 AI Foundry portal 的 "Connect to Foundry IQ" 流程。

Why: 我们的 HCP Agent 就是 Foundry Agent(通过 agent_sync_service 同步),应保持与 portal 一致的行为。MCPTool 是 Foundry 内部实现 "Connect to Foundry IQ" 的方式。

Rejected alternatives:

  • AzureAISearchTool(GA 但不是 portal 默认方式)
  • FileSearchTool(自动向量化但灵活性低)

SDK pattern:

from azure.ai.projects.models import MCPTool

mcp_tool = MCPTool(
    server_label="knowledge-base-{kb_name}",
    server_url=f"{search_endpoint}/knowledgebases/{kb_name}/mcp?api-version=2025-11-01-preview",
    require_approval="never",
    allowed_tools=["knowledge_base_retrieve"],
)

D-02: Agent 可绑定多个 Knowledge Base

Decision: 每个 HCP Agent 可连接多个 Knowledge Base,每个作为单独的 MCPTool 加入 Agent 的 tools 列表。

Why: HCP 可能需要产品知识库 + 医学文献知识库等多个来源。

Impact: Agent sync 时需合并已有 tools(如 Voice Live metadata)和新增的 KB tools。

D-03: MVP 只连接已有 KB,不做创建

Decision: 平台只做"列出 + 选择 + 连接"。Knowledge Base 的创建和文档上传在 AI Foundry portal 中完成。

Why: 这属于 Agent 能力配置范畴。KB 的创建和维护是其他模块(知识管理模块)的职责,不在 Agent 配置的范围内。Agent 配置只负责"选择并连接已有 KB"。

Impact: Admin 需要先在 AI Foundry portal 或知识管理模块中创建好 KB,然后在 HCP Agent 配置中选择连接。

D-04: 只读 + 连接操作范围(Agent 能力定义边界)

Decision: 平台通过 client.connections.list() 列出 AI Search Connections,通过 AI Search API 列出 Knowledge Bases,admin 选择后绑定到 Agent。不做创建/删除 KB。

Why: 职责分离 — Agent 配置模块定义"Agent 用哪些知识库",知识库本身的创建/维护/文档上传是知识管理模块的职责。Connections 是 project 级资源,SDK 只支持读取。

D-05: Knowledge Tab 恢复到 HCP Editor

Decision: 在 HCP 编辑器中恢复 Knowledge tab(Phase 14 添加后 Phase 15 移除的 tab),但这次填充真实功能而非占位符。

Layout: 参照 AI Foundry portal Knowledge 面板:

  • "Add" 按钮下拉:Connect to Foundry IQ
  • 已连接 KB 列表(名称、connection、状态)
  • 解绑按钮

D-06: Agent Sync 扩展 — tools 参数

Decision: 扩展 agent_sync_service.sync_agent_for_profile()PromptAgentDefinition 中加入 tools 参数,传入 KB 的 MCPTool 列表。

Current state: create_version() 只传 model + instructions + metadata。需要新增 tools 参数。

Merge strategy: Agent 可能同时有 Voice Live metadata + Knowledge MCPTools,tools 列表需要合并来自不同来源的 tools。

Prior Context Applied

  • Phase 11: Agent sync service (agent_sync_service.py) 完整的 CRUD + version 管理
  • Phase 14: Knowledge/Tools tab 曾存在于 HCP editor,后在 Phase 15 移除
  • Phase 16: Agent sync 包含 Voice Live metadata,需要与 KB tools 共存
  • Phase 05: Training Material 管理已存在但不在本 phase scope(MVP 不做自动索引)

Reusable Assets

Asset Location Reuse
AIProjectClient factory agent_sync_service._get_project_client() 复用 client.connections API
Agent sync flow sync_agent_for_profile() 扩展 tools 参数
i18n KB keys admin.json (hcp.tabKnowledge etc.) 已存在,扩展
HCP Editor VALID_TABS hcp-profile-editor.tsx 添加 "knowledge"
HCP Profile model hcp_profile.py 新增 KB 关联字段

New Dependencies

  • 可能不需要 azure-search-documents — 如果 client.connections + client.indexes 已足够列出 KB
  • 需要验证: AIProjectClient 是否有列出 Knowledge Bases 的 API(不是 indexes,是 KB)
  • 如果没有,可能需要 REST API 调用 AI Search 的 /knowledgebases endpoint

Scope Boundaries

In scope:

  • HCP Editor Knowledge tab UI(列出/连接/解绑 KB)
  • Backend API:list connections, list KBs, bind/unbind KB to HCP
  • Agent sync 扩展(tools 参数含 MCPTool)
  • DB migration(HCP profile KB 关联表)
  • 测试 + i18n

Out of scope(其他模块职责):

  • KB 创建/维护/文档上传 — 知识管理模块职责(可在 AI Foundry portal 或后续知识管理模块完成)
  • Phase 05 材料自动索引到 AI Search — 知识管理模块职责
  • Azure Blob Storage 集成 — 知识管理模块职责
  • Tools tab(Function Call 配置)— 后续 Agent 工具配置 phase

Open Questions for Research Phase

  1. AIProjectClient.indexes.list() 是否返回 Foundry IQ Knowledge Bases?还是需要直接调用 AI Search REST API /knowledgebases
  2. MCPTool 的 server_url 构建需要 AI Search endpoint — 这个从 connection.target 获取还是另外配置?
  3. 现有 create_version() 调用加入 tools 参数后是否需要同时保留 metadata(Voice Live config)?
  4. HCP Profile 和 KB 的关联关系:多对多(一个 KB 可被多个 HCP 使用)还是一对多?

Plans (3)

# Plan File Status
17-01 17-01-PLAN.md Complete
17-02 17-02-PLAN.md Complete
17-03 17-03-PLAN.md Complete

Research

Click to expand research notes

Phase 17 Research: Agent Knowledge Base (Foundry IQ) Configuration

Research date: 2026-04-10 SDK version: azure-ai-projects==2.0.1 All outputs verified against the installed SDK in backend/.venv


1. SDK API Inventory

1.1 AIProjectClient Top-Level Attributes

AIProjectClient attributes: ['close', 'get_openai_client', 'send_request']

The client does NOT expose .connections or .indexes as direct properties. Access pattern is through operations — need to verify runtime access (e.g., client.connections.list() may still work via dynamic attribute resolution at instance level).

1.2 ConnectionsOperations

from azure.ai.projects.operations import ConnectionsOperations
# Methods: ['get', 'get_default', 'list']

Signatures:

ConnectionsOperations.list(
    self,
    *,
    connection_type: Union[str, ConnectionType, None] = None,
    default_connection: Optional[bool] = None,
    **kwargs
) -> ItemPaged['Connection']

ConnectionsOperations.get(
    self,
    name: str,
    *,
    include_credentials: Optional[bool] = False,
    **kwargs
) -> Connection

Connection model attributes:

Attribute Description
id Connection resource ID
name Connection name
type ConnectionType enum value
target Endpoint URL for the connected resource
is_default Whether it is the default connection for its type
credentials Credential info (key, token, etc.)
metadata Dict of metadata

Usage to list AI Search connections:

connections = client.connections.list(
    connection_type=ConnectionType.AZURE_AI_SEARCH
)
for conn in connections:
    print(conn.name, conn.target)  # name and search endpoint

1.3 ConnectionType Enum

ConnectionType values:
  AZURE_OPEN_AI         = 'AzureOpenAI'
  AZURE_BLOB_STORAGE    = 'AzureBlob'
  AZURE_STORAGE_ACCOUNT = 'AzureStorageAccount'
  AZURE_AI_SEARCH       = 'CognitiveSearch'     # <-- THIS ONE
  COSMOS_DB             = 'CosmosDB'
  API_KEY               = 'ApiKey'
  APPLICATION_CONFIGURATION = 'AppConfig'
  APPLICATION_INSIGHTS  = 'AppInsights'
  CUSTOM                = 'CustomKeys'
  REMOTE_TOOL           = 'RemoteTool_Preview'

1.4 IndexesOperations

from azure.ai.projects.operations import IndexesOperations
# Methods: ['create_or_update', 'delete', 'get', 'list', 'list_versions']

Signatures:

IndexesOperations.list(self, **kwargs) -> ItemPaged['Index']
IndexesOperations.get(self, name: str, version: str, **kwargs) -> Index
IndexesOperations.list_versions(self, name: str, **kwargs) -> ItemPaged['Index']

Index model attributes:

Attribute Description
id Index resource ID
name Index name
version Version string
type Index type
description Description
tags Tags dict

Usage to list knowledge base indexes:

indexes = client.indexes.list()
for idx in indexes:
    print(idx.name, idx.version, idx.type)

2. Tool Types for Agents

2.1 Available Tool Classes (59 total, key ones below)

Class Purpose
AzureAISearchTool Attach Azure AI Search index as grounding tool
MCPTool Attach an MCP server (Foundry IQ, external tools)
FileSearchTool File-based search
CodeInterpreterTool Code interpreter
FunctionTool Custom function calling
BingGroundingTool Bing web grounding
OpenApiTool OpenAPI spec-based tool
WebSearchTool Web search

2.2 AzureAISearchTool (Recommended Path for Knowledge Base)

from azure.ai.projects.models import (
    AzureAISearchTool,
    AzureAISearchToolResource,
    AISearchIndexResource,
    AzureAISearchQueryType,
)

tool = AzureAISearchTool(
    azure_ai_search=AzureAISearchToolResource(
        indexes=[
            AISearchIndexResource(
                project_connection_id="<connection-name-or-id>",
                index_name="<index-name>",
                query_type=AzureAISearchQueryType.VECTOR_SEMANTIC_HYBRID,
                top_k=5,
                filter=None,
                index_asset_id=None,
            )
        ]
    )
)

AISearchIndexResource attributes:

Attribute Type Description
project_connection_id str Connection name or ID for the AI Search resource
index_name str Name of the search index
query_type AzureAISearchQueryType Query strategy
top_k int Number of documents to retrieve
filter str OData filter expression
index_asset_id str Optional asset ID

AzureAISearchQueryType enum:

SIMPLE                = 'simple'
SEMANTIC              = 'semantic'
VECTOR                = 'vector'
VECTOR_SIMPLE_HYBRID  = 'vector_simple_hybrid'
VECTOR_SEMANTIC_HYBRID = 'vector_semantic_hybrid'

Constraint: Maximum 1 index resource per agent (per SDK docs).

2.3 MCPTool (Alternative Path for Foundry IQ)

from azure.ai.projects.models import MCPTool

tool = MCPTool(
    server_label="foundry-iq",                    # Required: label for tool calls
    server_url="https://<endpoint>/mcp",           # One of server_url or connector_id
    connector_id=None,                             # Pre-built connector (Dropbox, Gmail, etc.)
    authorization="Bearer <token>",                # OAuth token if needed
    server_description="Foundry IQ knowledge base",
    headers={"x-custom": "value"},                 # Optional headers
    allowed_tools=["search", "retrieve"],           # Filter which tools to expose
    require_approval="never",                      # "always" | "never" | MCPToolRequireApproval
    project_connection_id="<connection-id>",        # Connection storing auth details
)

MCPTool attributes:

Attribute Required Description
server_label Yes Label identifying the MCP server in tool calls
server_url One of url/connector MCP server URL
connector_id One of url/connector Pre-built service connector ID
authorization No OAuth access token
server_description No Description for context
headers No Custom HTTP headers
allowed_tools No Filter to specific tools (list or MCPToolFilter)
require_approval No Approval mode for tool use
project_connection_id No Connection ID storing auth details

3. PromptAgentDefinition (Tools Integration)

from azure.ai.projects.models import PromptAgentDefinition

Confirmed attributes:

Attribute Description
instructions Agent system prompt
model Model deployment name
tools List of Tool objects (AzureAISearchTool, MCPTool, etc.)
tool_choice Tool selection strategy
temperature Sampling temperature
top_p Top-p sampling
reasoning Reasoning configuration
structured_inputs Structured input config
rai_config Responsible AI config
text Text output config
kind Definition kind

Usage with tools:

definition = PromptAgentDefinition(
    model="gpt-4o",
    instructions="You are an HCP...",
    tools=[
        AzureAISearchTool(
            azure_ai_search=AzureAISearchToolResource(
                indexes=[
                    AISearchIndexResource(
                        project_connection_id="my-search-connection",
                        index_name="product-knowledge-base",
                        query_type=AzureAISearchQueryType.VECTOR_SEMANTIC_HYBRID,
                        top_k=5,
                    )
                ]
            )
        )
    ],
)

4. Current agent_sync_service.py Pattern

File: backend/app/services/agent_sync_service.py

4.1 create_agent() (line ~435)

async def create_agent(
    db: AsyncSession,
    name: str,
    instructions: str,
    model: str | None = None,
    *,
    metadata: dict[str, str] | None = None,
    endpoint_override: str = "",
    key_override: str = "",
) -> dict:
    definition = PromptAgentDefinition(model=model, instructions=instructions)
    result = await asyncio.to_thread(
        client.agents.create_version,
        agent_name=agent_name,
        definition=definition,
        description=f"HCP Agent: {name}",
        metadata=metadata,
    )

4.2 update_agent() (line ~495)

Same pattern — creates PromptAgentDefinition(model=model, instructions=instructions) with NO tools parameter.

4.3 What Needs to Change

Both create_agent() and update_agent() must accept an optional tools parameter:

async def create_agent(
    db, name, instructions, model=None, *,
    metadata=None,
    tools: list | None = None,    # NEW
    endpoint_override="", key_override="",
) -> dict:
    definition = PromptAgentDefinition(
        model=model,
        instructions=instructions,
        tools=tools or [],         # NEW — pass tools list
    )

5. Current HCP Profile Model

File: backend/app/models/hcp_profile.py

No knowledge base fields exist. Current fields relevant to agent sync:

Field Type Description
agent_id String(100) Foundry Agent name/ID
agent_version String(50) Current agent version
agent_sync_status String(20) none/pending/synced/failed
agent_sync_error Text Error message

5.1 DB Migration Plan

Option A: New columns on hcp_profiles (Recommended for MVP)

Add to hcp_profiles table:

# Knowledge base configuration
kb_connection_id: Mapped[str] = mapped_column(String(255), default="")
kb_index_name: Mapped[str] = mapped_column(String(255), default="")
kb_query_type: Mapped[str] = mapped_column(String(50), default="vector_semantic_hybrid")
kb_top_k: Mapped[int] = mapped_column(default=5)
kb_enabled: Mapped[bool] = mapped_column(Boolean, default=False)

Option B: Separate hcp_knowledge_configs table (Better for multi-index future)

class HcpKnowledgeConfig(Base, TimestampMixin):
    __tablename__ = "hcp_knowledge_configs"
    hcp_profile_id: FK -> hcp_profiles.id (unique, 1:1)
    connection_id: String(255)   # AI Search connection name
    index_name: String(255)      # Index name
    query_type: String(50)       # AzureAISearchQueryType value
    top_k: int                   # default 5
    filter_expression: Text      # OData filter (optional)
    is_enabled: bool             # default False

Recommendation: Option A (columns on hcp_profiles) for simplicity. The SDK limits agents to 1 index anyway. A separate table adds join complexity without current benefit.

5.2 Alembic Migration

Latest migration: o18a_rename_vl_model_instruction.py

New migration needed: p19a_add_kb_fields_to_hcp_profiles.py


6. Backend API Plan

6.1 New Endpoints

GET  /api/v1/knowledge-base/connections
  -> List AI Search connections from Foundry
  -> Returns: [{ name, target, is_default }]

GET  /api/v1/knowledge-base/indexes
  -> List indexes from Foundry project
  -> Returns: [{ name, version, type, description }]

GET  /api/v1/knowledge-base/indexes/{connection_name}
  -> List indexes within a specific AI Search connection
  -> (May require direct Azure Search REST call, not SDK)

PUT  /api/v1/hcp-profiles/{id}/knowledge-base
  -> Configure KB for an HCP profile
  -> Body: { connection_id, index_name, query_type, top_k, enabled }
  -> Triggers agent re-sync with tools parameter

GET  /api/v1/hcp-profiles/{id}/knowledge-base
  -> Get current KB config for an HCP profile

6.2 New Service: knowledge_base_service.py

async def list_search_connections(db: AsyncSession) -> list[dict]:
    """List Azure AI Search connections from Foundry project."""
    endpoint, key = await get_project_endpoint(db)
    client = _get_project_client(endpoint, key)
    connections = await asyncio.to_thread(
        client.connections.list,
        connection_type=ConnectionType.AZURE_AI_SEARCH,
    )
    return [{"name": c.name, "target": c.target, "is_default": c.is_default} for c in connections]

async def list_indexes(db: AsyncSession) -> list[dict]:
    """List all indexes in the Foundry project."""
    endpoint, key = await get_project_endpoint(db)
    client = _get_project_client(endpoint, key)
    indexes = await asyncio.to_thread(client.indexes.list)
    return [{"name": i.name, "version": i.version, "type": i.type} for i in indexes]

def build_search_tool(connection_id: str, index_name: str, query_type: str, top_k: int):
    """Build AzureAISearchTool from config."""
    return AzureAISearchTool(
        azure_ai_search=AzureAISearchToolResource(
            indexes=[AISearchIndexResource(
                project_connection_id=connection_id,
                index_name=index_name,
                query_type=query_type,
                top_k=top_k,
            )]
        )
    )

7. Frontend Component Plan

7.1 Knowledge Tab in HCP Profile Editor

Location: frontend/src/components/coach/HcpKnowledgeTab.tsx

Structure:

KnowledgeTab
  +-- EnableToggle (kb_enabled on/off)
  +-- ConnectionSelector (dropdown, fetched from GET /knowledge-base/connections)
  +-- IndexSelector (dropdown, fetched from GET /knowledge-base/indexes)
  +-- QueryTypeSelector (dropdown: simple, semantic, vector, hybrid variants)
  +-- TopKSlider (1-20, default 5)
  +-- SaveButton (PUT /hcp-profiles/{id}/knowledge-base)
  +-- SyncStatusBadge (shows if agent re-sync succeeded)

7.2 New TanStack Query Hooks

// frontend/src/hooks/useKnowledgeBase.ts
useSearchConnections()      // GET /knowledge-base/connections
useIndexes()                // GET /knowledge-base/indexes
useHcpKnowledgeConfig(id)   // GET /hcp-profiles/{id}/knowledge-base
useUpdateKnowledgeConfig()  // PUT /hcp-profiles/{id}/knowledge-base (mutation)

7.3 New TypeScript Types

// frontend/src/types/knowledgeBase.ts
interface SearchConnection {
  name: string;
  target: string;
  is_default: boolean;
}

interface SearchIndex {
  name: string;
  version: string;
  type: string;
  description: string;
}

interface KnowledgeBaseConfig {
  connection_id: string;
  index_name: string;
  query_type: 'simple' | 'semantic' | 'vector' | 'vector_simple_hybrid' | 'vector_semantic_hybrid';
  top_k: number;
  enabled: boolean;
}

8. Key Decisions and Risks

8.1 AzureAISearchTool vs MCPTool

Criterion AzureAISearchTool MCPTool
Simplicity Simpler, purpose-built More flexible, more config
SDK support First-class, well-documented Newer, server_url construction unclear
Index limit 1 per agent Depends on MCP server
Auth Via connection_id Needs OAuth or headers
Foundry IQ alignment Native integration Would need Foundry IQ MCP endpoint URL

Recommendation: Use AzureAISearchTool for Phase 17. It is the natural fit for connecting agents to Azure AI Search indexes. MCPTool is better suited for external MCP servers (Foundry IQ's MCP endpoint is not yet well-documented for direct construction).

8.2 Risks

  1. client.connections runtime accessAIProjectClient doesn't show connections in dir(). Need to verify at runtime with a real endpoint that client.connections.list() works. (It should via dynamic binding, but must test.)

  2. client.indexes runtime access — Same concern. IndexesOperations class exists but client attribute is not statically visible.

  3. Index listing within a specific AI Search connection — The SDK IndexesOperations.list() lists project-level indexes, NOT indexes within a specific AI Search service. To list indexes within a specific Azure AI Search connection, a direct REST call to the Search service endpoint (from connection.target) may be needed: GET https://<search-endpoint>/indexes?api-version=2024-07-01.

  4. Agent re-sync on KB change — Changing KB config must trigger a full agent version bump via create_version. This is already the pattern for updates, but the tools parameter is new.

  5. 1 index limit — SDK doc says max 1 index per AzureAISearchToolResource.indexes. This is fine for MVP but constrains multi-index scenarios.


9. Implementation Sequence

  1. DB migration — Add KB columns to hcp_profiles
  2. Pydantic schemas — Add KnowledgeBaseConfig request/response schemas
  3. knowledge_base_service.py — List connections, list indexes, build_search_tool()
  4. Modify agent_sync_service.py — Add tools param to create/update_agent, build tools from KB config
  5. API router/knowledge-base/connections, /knowledge-base/indexes, HCP KB endpoints
  6. Frontend types + hooks — TypeScript types, TanStack Query hooks
  7. Frontend KnowledgeTab component — UI for configuring KB per HCP
  8. Integration into HCP editor — Add Knowledge tab to existing HCP profile editor
  9. Tests — Unit tests for service, API integration tests, E2E for UI flow
⚠️ **GitHub.com Fallback** ⚠️