AI Code Import
code-import SQS キューからコード取り込みジョブを処理する。コンポーネントのソースコード(およびオプションのスクリーンショット)を解析し、セマンティックワード、視覚的特徴、汎用 source context を抽出、512 次元埋め込みベクトル(visual + semantic + context)を生成し、DocumentDB の code コレクションにアップサートした後、Webhook でバックエンドにステータスを通知する。
置き換え対象: guinness-ai-develop の V1 code import predecessor
キュー: code-import
最大実行時間: 約 1〜3 分
ソース: guinness-ai-v2(新規リポジトリ)
技術スタック
- ランタイム: Python 3.12 on AWS Lambda
- AI フレームワーク: PydanticAI(エージェントオーケストレーション、プロバイダー非依存)
- LLM:
DESC_MODEL環境変数で設定(例:openai:gpt-5.4-nano)— コード解析 + オプションの Vision - 埋め込み:
EMBEDDING_MODEL環境変数で設定(例:text-embedding-3-small、512 次元: visual + semantic + context)—openaiSDK 直呼び出し - データベース: Amazon DocumentDB(MongoDB 互換) —
codeコレクション、AI 専用 - ストレージ: Amazon S3(コンポーネントのスクリーンショット、オプション)
- キュー: AWS SQS(
code-importキュー) - ステータス通知: Webhook
POST /v1/webhooks/ai-status→ guinness-backend - MySQL/PostgreSQL 非アクセス: データベース分離を徹底
V1 との主な変更点
| 項目 | V1 | V2(code-import) |
|---|---|---|
| AI フレームワーク | LangGraph StateGraph |
PydanticAI — 2 エージェント(run_sync) |
| スクリーンショット | img_url 必須 |
img_url 任意 — なしの場合は visual をテキストのみで推論 |
| ソースコードの LLM 利用 | 保存のみ、解析なし | Semantic エージェントが source_code + css_code を読む |
| 埋め込み | 1 本(vision キーワードの vector_embedding) |
3 本 — visual + semantics + context |
| Visual LLM 入力 | 画像のみ | img_url あり: 画像 + CSS / なし: コード + CSS のみ |
| DB 書き込み | MySQL + DocumentDB | DocumentDB のみ + Webhook(RDB 非アクセス) |
| DocDB コレクション | legacy flat code-like collection | code |
| CSS | 未保存 | css_code(任意) |
| バッチ処理 | 最初の失敗で全体リトライ | batchItemFailures(レコード単位) |
organization_id |
DocDB になし | 全ドキュメントに保存 |
フィールド単位の公式契約: io-definition.ja.md。
処理フロー
flowchart TD
A["SQS: code-import\n(code_id, source_code, img_url?)"] --> B["パース + 検証 CodeImportMessage"]
B --> C["Semantic エージェント — テキストのみ\nsource_code + css_code → semantic_words"]
B --> X["決定的 source parser\nimports, exports, tags, tokens,\nfamily, variant, level"]
B --> D{img_url あり?}
D -->|Yes| E["S3 GET スクリーンショット\n(最大 10 MB)"]
E --> F["Visual エージェント — マルチモーダル\n画像 + CSS → visual_features"]
D -->|No| G["Visual エージェント — テキストのみ\nsource_code + CSS → visual_features"]
F --> H
G --> H
C --> H
X --> H
H["OpenAI Embeddings — 1 回バッチ\n[visual_features, semantic_words, context_text] → 512 次元"]
H --> I["CodeDocument 構築\nDocumentDB upsert _id=code_id"]
I --> J["POST webhook success"]
style A fill:#f9f,stroke:#333
style C fill:#bbf,stroke:#333
style F fill:#bbf,stroke:#333
style G fill:#bbf,stroke:#333
style I fill:#bfb,stroke:#333
style J fill:#fdb,stroke:#333
実装: apps/code-import/src/code_import/service.py(process_record)。エージェントは handler.py で packages/agentic から構築。
埋め込み戦略
design-import とは異なり、visual と semantic は 1 回の vision で取るわけではない。Semantic と visual は別エージェントで抽出し、context は source と任意の汎用 metadata から決定的に導出する。
| 埋め込み | エージェント | 入力 | エンコード内容 | des2code での用途 |
|---|---|---|---|---|
semantics |
Code Semantics | source_code, css_code |
目的・機能キーワード(5〜10) | デザインが求める機能に近いコンポーネント |
visual |
Code Visual | スクショ + CSS、またはコード/CSS のみ | visual_features テキスト → 埋め込み |
デザインに見た目が近いコンポーネント |
context |
決定的 parser | source、CSS、name、matching hints | imports、exports、JSX/HTML tags、referenced components、source tokens、family、variant、level | 構造、階層、コンポーネント構成で関連する code を探す |
全ベクトルは 1 回の embeddings.create で生成(モデル・次元のずれを防止)。
Code Import は最小限の matching contract にする。SQS payload から受け取る任意 matching hints は component level、family、variant のみで、それ以外の context は source 自体から導出する。
1. SQS メッセージスキーマ(入力)
エンベロープ
バックエンド(apps/app/src/services/code.ts)が code-import キューにエンキューする。Lambda は標準の SQSEvent ラッパーで受信する:
{
"Records": [{
"messageId": "0192a3b4-c5d6-7e8f-9a0b-1c2d3e4f5a6b",
"body": "{\"code_id\":\"660e8400-e29b-41d4-a716-446655440001\",\"organization_id\":1,\"project_id\":42,\"name\":\"button-primary\",\"type\":1,\"based_on\":0,\"source_code\":\"<button className='btn btn-primary'>Click me</button>\",\"css_code\":\".btn-primary { background:#007bff; }\",\"img_url\":\"s3://bucket/code/42_button.png\"}",
"attributes": { "ApproximateReceiveCount": "1" },
"eventSource": "aws:sqs"
}]
}
Body フィールド
Records[0].body は JSON 文字列。パース後:
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
code_id |
string (UUID) | Yes | 主キー。PG code.id および DocumentDB _id と同一値。 |
organization_id |
int | Yes | 所属組織。DocumentDB のテナント分離に使用。 |
project_id |
int | Yes | 所属プロジェクト。ベクトル検索の $match スコープに使用。 |
name |
string | Yes | 人間可読な名前(例: "button-primary")。 |
type |
int | Yes | 0 = page、1 = code。 |
based_on |
int | Yes | 0 = imported、1 = design 由来、2 = wireframe 由来。 |
source_code |
string | Yes | コンポーネントのソース(JSX/TSX/HTML)。 |
css_code |
string | No | オプション CSS。存在すればそのまま保存。 |
img_url |
string | No | スクリーンショットの S3 URL(オプション)。省略時は視覚的特徴をコードから推論。 |
component_level |
string | No | atom、molecule、organism、template、page などの任意 level。 |
family |
string | No | 任意 component family。省略時は name/source tokens から導出。 |
variant |
string | No | 任意 variant。省略時は name/source tokens から導出。 |
バリデーションルール
code_idは RFC 4122 UUID v4 に準拠。type ∈ {0, 1}、based_on ∈ {0, 1, 2}— それ以外は拒否。source_codeは非空(長さ ≥ 1、推奨 ≤ 200 KB)。img_url(存在する場合)は次のいずれかの形式:s3://bucket/key、https://bucket.s3.<region>.amazonaws.com/key、https://s3.<region>.amazonaws.com/bucket/key。URL エンコードキーも受け付ける。
Pydantic モデル
from pydantic import BaseModel, Field
class CodeImportMessage(BaseModel):
code_id: str = Field(..., description="UUID v4; PG code.id および DocDB _id と一致")
organization_id: int
project_id: int
name: str
type: int = Field(..., ge=0, le=1, description="0=page, 1=code")
based_on: int = Field(..., ge=0, le=2, description="0=imported, 1=design, 2=wireframe")
source_code: str = Field(..., min_length=1)
css_code: str | None = None
img_url: str | None = None
component_level: str | None = None
family: str | None = None
variant: str | None = None
注意(V1 → V2 リネーム): V2 では legacy import identity fields を統合された
codeコレクションに合わせてcode_id/nameに正規化。
2. Webhook ペイロードスキーマ(HTTP 出力)
処理完了後、ワーカーは WEBHOOK_BASE_URL(POST /v1/webhooks/ai-status)に 1 回 POST する。認証は X-API-Key(タイミングセーフ比較)。受信側コントラクトは ai-status webhook を参照。
成功時
{
"type": "code-import",
"recordId": "660e8400-e29b-41d4-a716-446655440001",
"projectId": 42,
"organizationId": 1,
"status": "success",
"result": {
"keywords": ["submit", "checkout", "transaction", "action", "primary"],
"embeddingDims": 512
}
}
失敗時
{
"type": "code-import",
"recordId": "660e8400-e29b-41d4-a716-446655440001",
"projectId": 42,
"organizationId": 1,
"status": "failed"
}
フィールド一覧
| フィールド | 型 | 説明 |
|---|---|---|
type |
string | 常に "code-import"(ディスクリミネータ)。 |
recordId |
string | SQS body の code_id をエコー。バックエンドが PostgreSQL の code 行を更新する際に使用。 |
projectId |
int | project_id をエコー。 |
organizationId |
int | organization_id をエコー。backend scope validation に使用。 |
status |
string | "success" または "failed"。 |
result |
object | status="success" の場合のみ存在。 |
result.keywords |
string[] | ソースコードから抽出されたセマンティックワード(5–10 件)。 |
result.embeddingDims |
int | 512(HNSW インデックス次元と一致)。 |
型整合性に関する注意: このフローでは backend
code.idが UUID 文字列のため、recordIdは string。backend webhook contract はcode_idと同じ値を受け付ける必要がある。
送信タイミング
| イベント | 送信タイミング | Body |
|---|---|---|
| 全工程が例外なく完了 | DocumentDB アップサート成功後 | 成功ペイロード |
process_record() で例外発生時 |
例外を再 raise する直前 | 失敗ペイロード |
HTTP 呼び出しは httpx を使用、timeout=10s, retries=2(指数バックオフ)。Webhook 自体の失敗は retryable processing failure として扱い、worker は SQS が再配送できるように再 raise する。
3. PydanticAI — LLM ロール定義
ワーカーは 2 つのロールに対応した 2 つの専用 LLM 呼び出し を行う。
| ロール | アーキテクチャノード | 入力 | 出力 |
|---|---|---|---|
| Code Analysis LLM | C — ソースコード解析 → semantic words |
ソースコード + CSS(テキスト) | semantic_words リスト |
| Vision LLM | F — 視覚特徴抽出 / G — コード構造から推論 |
スクリーンショット(ある場合)またはソースコード + CSS | visual_features 文字列 |
両呼び出しとも同じ DESC_MODEL 環境変数(provider:model 形式、例: openai:gpt-5.4-nano)を使用。独立した呼び出しであり、各出力は別々に埋め込まれる。
3.1 Code Analysis LLM(テキスト専用)
アーキテクチャノード C に対応。ソースコード(およびオプションの CSS)を読み、コンポーネントが 何をするか を表す 5–10 個のセマンティックキーワードを出力。
from pydantic_ai import Agent
from pydantic import BaseModel, Field
class CodeSemantics(BaseModel):
semantic_words: list[str] = Field(
min_length=5, max_length=10,
description="コンポーネントの目的・機能・動作を表す 5–10 個のキーワード",
)
code_analysis_llm = Agent(
DESC_MODEL,
output_type=CodeSemantics,
instructions=(
"あなたはフロントエンドコードアナリストです。コンポーネントのソースコードと "
"オプションの CSS が与えられたら、目的・機能・動作を表す 5–10 個の "
"簡潔なキーワードを抽出してください。例: 'submit', 'checkout', 'navigation', "
"'modal', 'form', 'pagination'。視覚的スタイルはここでは記述しない — "
"別途扱う。"
),
)
入力(ワーカーが構築): 以下の形式の単一ユーザーメッセージ
出力: CodeSemantics.semantic_words → Webhook の result.keywords および semantic 埋め込み に使用。
3.2 Vision LLM(vision 対応、条件分岐)
アーキテクチャノード F(スクリーンショットあり)および G(スクリーンショットなし — コード構造から推論)に対応。img_url の有無で分岐。
class VisualFeatures(BaseModel):
visual_features: str = Field(
min_length=20,
description="視覚的記述: 色、形、間隔、レイアウト、タイポグラフィ、全体的な美学",
)
vision_llm = Agent(
DESC_MODEL,
output_type=VisualFeatures,
instructions=(
"あなたは UI デザインアナリストです。コンポーネントの視覚スタイル "
"(色、形、間隔、レイアウト、タイポグラフィ、全体的な美学)を記述してください。"
"スクリーンショットがある場合は画像を優先。"
"ソースコード/CSS のみの場合は、クラス名・インラインスタイル・構造から推論してください。"
),
)
| 分岐 | LLM 入力 | アーキテクチャノード |
|---|---|---|
img_url あり |
スクリーンショットの base64 + (オプションの)CSS テキスト | F — Vision LLM がピクセルレベルの特徴を抽出 |
img_url なし |
source_code + css_code(テキストのみ) | G — コード構造から視覚特徴を推論 |
出力: VisualFeatures.visual_features → visual 埋め込み に使用。
4. 埋め込み生成
PydanticAI は埋め込みを扱わない。ワーカーは openai SDK を直接呼び出す。コストとレイテンシ削減のため、全埋め込みを 1 回のバッチ API 呼び出しで生成。
from openai import AsyncOpenAI
client = AsyncOpenAI() # OPENAI_API_KEY を環境変数から読み取り
async def generate_embeddings(
visual_text: str,
semantic_words: list[str],
context_text: str,
) -> tuple[list[float], list[float], list[float]]:
response = await client.embeddings.create(
model=EMBEDDING_MODEL, # 例: "text-embedding-3-large"
input=[visual_text, " ".join(semantic_words), context_text],
dimensions=512,
)
return response.data[0].embedding, response.data[1].embedding, response.data[2].embedding
| 埋め込み | 入力テキスト | ソースエージェント | インデックスフィールド |
|---|---|---|---|
visual |
visual_features |
Visual Agent | visual.vector_embedding |
semantics |
" ".join(semantic_words) |
Semantic Agent | semantics.vector_embedding |
context |
source parser 由来の context_text |
決定的 parser | context.vector_embedding |
全ベクトルは DocumentDB の HNSW インデックスに合わせて 512 次元。
5. DocumentDB 操作
5.1 アップサート
アップサートは 冪等: 同じ code_id で再処理しても最終状態は同じ。
5.2 ドキュメント構造(code コレクション)
{
"_id": "660e8400-e29b-41d4-a716-446655440001",
"organization_id": 1,
"project_id": 42,
"name": "button-primary",
"type": 1,
"based_on": 0,
"index_schema_version": "2026.05.1",
"source_code": "<button className='btn btn-primary'>Click me</button>",
"css_code": ".btn-primary { background:#007bff; border-radius:8px; }",
"code_context": {
"component_level": "atom",
"family": "button",
"variant": "primary",
"imports": ["react"],
"exports": ["Button"],
"referenced_components": ["button"],
"source_tokens": ["button", "primary", "click", "btn-primary"]
},
"visual": {
"metadata": {
"name": "button-primary",
"image_url": "s3://bucket/code/42_button.png",
"encoder": "text-embedding-3-small@512"
},
"vector_embedding": [0.12, -0.04, 0.88, "..."]
},
"semantics": {
"metadata": {
"words": ["submit", "checkout", "transaction", "action", "primary"]
},
"vector_embedding": [0.45, 0.22, -0.10, "..."]
},
"context": {
"metadata": {
"context_text": "level=atom family=button variant=primary exports=Button tags=button tokens=button primary click btn-primary"
},
"vector_embedding": [0.18, 0.31, -0.22, "..."]
}
}
| フィールド | ソース | 備考 |
|---|---|---|
_id |
SQS body の code_id |
UUID; PG code.id と一致 |
organization_id |
SQS body | テナント分離 |
project_id |
SQS body | ベクトル検索の $match スコープ |
name, type, based_on |
SQS body | そのまま |
source_code, css_code |
SQS body | そのまま; css_code は省略可 |
index_schema_version |
schemas.py の INDEX_SCHEMA_VERSION |
形状/エンコーダ変更時にバンプ |
code_context |
決定的 parser + 任意 matching hints | context retrieval と reranking に使う matching evidence |
visual.metadata.image_url |
SQS img_url または null(テキストのみ visual) |
— |
visual.metadata.encoder |
インデックス時の {model}@{dims} |
— |
visual.vector_embedding |
visual_features 文字列の埋め込み |
512 次元 |
semantics.metadata.words |
Code Semantics エージェント出力 | 5–10 個の文字列 |
semantics.vector_embedding |
semantic_words 結合文字列の埋め込み |
512 次元 |
context.metadata.context_text |
決定的 context text | context retrieval に使用 |
context.vector_embedding |
context_text 文字列の埋め込み |
512 次元 |
5.3 ベクトルインデックス
packages/models/documentdb/code.py で起動時に 1 回だけ作成(冪等):
| インデックス | フィールド | 型 | 次元 | 類似度 |
|---|---|---|---|---|
visualVectorIndex |
visual.vector_embedding |
HNSW | 512 | cosine |
semanticVectorIndex |
semantics.vector_embedding |
HNSW | 512 | cosine |
contextVectorIndex |
context.vector_embedding |
HNSW | 512 | cosine |
HNSW パラメータ: m=16、efConstruction=64。
5.4 design-import / des2code とのクロスモーダルブリッジ
des2code は design ドキュメントのベクトルと evidence を使い、visual、semantic、context signal で code コレクションを検索する。
| des2code 検索 | design 側クエリ | code 側パス |
|---|---|---|
| Visual | design.visual.vector_embedding |
code.visual.vector_embedding |
| Semantic | design.semantics.vector_embedding |
code.semantics.vector_embedding |
| Context / structural | design.structural.vector_embedding と design.query_terms |
code.context.vector_embedding と code_context |
semantic の生成元はワーカーごとに異なります:
| ワーカー | semantics.metadata.words の出所 |
|---|---|
| design-import | 1 回の vision → デザイン画像から semantic_words |
| code-import | テキスト専用エージェント → ソースコード + CSS から |
埋め込みモデル・512 次元は共通のため検索は可能ですが、semantic 軸は「同じ画像を二重に渡す」ものではなく、意図のブリッジです。生成時のコンポーネント画像は code.visual.metadata.image_url(コンポーネントごとに任意)。
6. エラーハンドリング
アプリケーションレベルのリトライなし — SQS のリドライブに依存。
def handler(event, context):
if "Records" not in event:
raise ValueError("Invalid SQS event")
for record in event["Records"]:
try:
process_record(record)
except Exception as e:
logger.error(f"Failed: {record.get('messageId')} — {e}")
send_webhook(status="failed", ...) # ベストエフォート
raise # SQS がバッチをリトライ
失敗マトリクス
| ステージ | 例外クラス | 動作 | Webhook 送信? |
|---|---|---|---|
SQS エンベロープに Records なし |
ValueError |
再 raise → SQS リトライ | ❌(レコードコンテキストなし) |
| Body JSON パース失敗 | json.JSONDecodeError |
再 raise → SQS リトライ | ❌(code_id なし) |
| Pydantic バリデーション失敗 | ValidationError |
再 raise → SQS リトライ | ⚠️ 部分的(code_id がパース可能ならベストエフォート) |
| S3 ダウンロード失敗 | botocore.exceptions.ClientError |
再 raise → SQS リトライ | ✅ failed |
| LLM 呼び出し失敗(semantic / visual) | pydantic_ai.exceptions.AgentRunError |
再 raise → SQS リトライ | ✅ failed |
| 埋め込み API 失敗 | openai.APIError |
再 raise → SQS リトライ | ✅ failed |
| DocumentDB 書き込み失敗 | pymongo.errors.PyMongoError |
再 raise → SQS リトライ | ✅ failed |
| Webhook POST 失敗 | httpx.HTTPError |
log して SQS retry のため再 raise | n/a |
| 最大 SQS リトライ超過 | — | DLQ へ配送(Terraform で設定) | n/a |
リトライ可能 vs 終端
| 種類 | 例 | SQS の扱い |
|---|---|---|
| 終端(リトライ無意味) | 不正な JSON、バリデーションエラー | 初回失敗で DLQ |
| リトライ可能(一時的) | S3 5xx、OpenAI 429、DocDB 接続リセット | 指数リトライ後 DLQ |
区別は SQS パーシャルバッチレスポンス(batchItemFailures)で実装。
7. フォルダ構成
guinness-ai-v2/
packages/
agentic/
__init__.py
orchestrator.py # build_manager_agent(), build_tool_agent() — PydanticAI
agents/
__init__.py
vision.py # Vision LLM + DesignDescription (design-import 用)
code_semantics.py # ★ Code Analysis LLM + CodeSemantics (code-import 用, arch node C)
code_visual.py # ★ Vision LLM + VisualFeatures (code-import 用, arch nodes F/G)
code_gen.py # コード生成 LLM (des2code 用)
models/
documentdb/
__init__.py # initialize_collections()
design.py # DesignCollection
code.py # ★ CodeCollection + visual / semantic インデックス
helpers/
s3.py # parse_s3_url(), download_image_from_s3()
embedding.py # generate_embeddings() — 共有 openai SDK ユーティリティ
webhook.py # send_webhook() — 共有 httpx POST
utils/
settings.py # 共有 Pydantic Settings 基底
documentdb.py # 共有 DocumentDB 接続シングルトン
apps/
code-import/ # リポジトリ上のディレクトリ(ハイフン); uv ワークスペースのパス
pyproject.toml # Hatch プロジェクト名 code_import と import パスが一致
Dockerfile
README.md
__tests__/ # 未配置 — test-cases.ja.md に従って追加
src/
code_import/ # Python パッケージ(アンダースコア)
handler.py # Lambda エントリ lambda_handler(Dockerfile CMD)
config.py # Pydantic Settings のたたき台
schemas.py # CodeImportMessage / CodeDocument / Webhook(拡張予定)
prompts.py # プロンプト文字列・バージョン
db.py # (予定)DocumentDB アップサートヘルパー
ファイル責務(アプリレベル)
| パス | 責務 |
|---|---|
src/code_import/handler.py |
Lambda lambda_handler(event, context) — SQS バッチ処理とレコード単位ワークフロー |
src/code_import/config.py |
Pydantic Settings のたたき台 — 機能追加に合わせて環境変数を増やす |
src/code_import/schemas.py |
入力 / 出力モデル(CodeImportMessage, DocDB / Webhook ペイロード) |
src/code_import/prompts.py |
プロンプト資産 / バージョン |
(予定)src/code_import/db.py |
upsert_code(document) — DocDB 書き込み |
ファイル責務(共有パッケージ)
| ファイル | 責務 |
|---|---|
packages/agentic/agents/code_semantics.py |
Code Analysis LLM(arch ノード C) + CodeSemantics 出力モデル |
packages/agentic/agents/code_visual.py |
Vision LLM(arch ノード F/G) + VisualFeatures 出力モデル |
packages/models/documentdb/code.py |
CodeCollection クラス、ベクトルインデックス作成 |
packages/helpers/embedding.py |
generate_embeddings() — 共有 openai SDK 呼び出し |
packages/helpers/webhook.py |
send_webhook() — 共有 httpx POST |
V1 から削除: config/mysql.py、すべての save_*_to_mysql ヘルパー(V2 では MySQL アクセスなし)。
8. 環境変数
| 変数 | 説明 | 例 |
|---|---|---|
OPENAI_API_KEY |
OpenAI キー(PydanticAI と openai SDK の両方で使用) |
sk-... |
DESC_MODEL |
コード解析 + vision モデル(プロバイダー前置詞付き) | openai:gpt-5.4-nano |
EMBEDDING_MODEL |
埋め込みモデル | text-embedding-3-large |
EMBEDDING_DIMENSIONS |
ベクトル次元 | 512 |
DOCUMENTDB_CONNECTION_STRING |
DocumentDB 接続文字列 | mongodb://... |
DOCUMENTDB_NAME |
DocumentDB データベース名 | guinness_ai |
CODE_TABLE_NAME |
DocumentDB コレクション名 | code |
DOCUMENTDB_CA_PATH |
TLS CA(Lambda) | /var/task/global-bundle.pem |
WEBHOOK_BASE_URL |
バックエンド Webhook URL(プライベート VPC) | https://api.internal/v1/webhooks/ai-status |
WEBHOOK_API_KEY |
X-API-Key として送信する API キー(Secrets Manager から) |
(secret) |
V2 で不要(Terraform が管理): SQS_*_QUEUE_URL、S3_BUCKET。
V1 から削除: DATABASE_RDS_PROXY_ENDPOINT、DATABASE_NAME、DATABASE_USER、DATABASE_PASSWORD、DATABASE_PORT(V2 では MySQL なし)。
9. 依存パッケージ
| パッケージ | 用途 |
|---|---|
openai |
OpenAI SDK(埋め込み) |
pydantic-ai |
PydanticAI(エージェントオーケストレーション、プロバイダー非依存) |
pydantic |
データモデル、構造化出力 |
pydantic-settings |
環境変数設定 |
pymongo |
DocumentDB ドライバー |
boto3 |
AWS SDK(S3 ダウンロード) |
loguru |
構造化ログ |
httpx |
HTTP クライアント(Webhook POST) |
V1 から削除: langchain-openai、langgraph、PyMySQL。
10. エンドツーエンドシーケンス
sequenceDiagram
participant SQS as code-import SQS
participant L as Lambda code-import
participant S3 as S3
participant SA as Semantic Agent (PydanticAI)
participant VA as Visual Agent (PydanticAI)
participant E as OpenAI Embeddings
participant D as DocumentDB (code)
participant WH as POST /v1/webhooks/ai-status
SQS->>L: SQSEvent (1 record)
L->>L: parse + validate (CodeImportMessage)
L->>L: deterministic source parser -> code_context + context_text
L->>SA: source_code + css_code
SA-->>L: semantic_words[5..10]
alt img_url あり
L->>S3: GetObject(img_url)
S3-->>L: bytes
L->>VA: image (base64) + css_code
else img_url なし
L->>VA: source_code + css_code (テキストのみ)
end
VA-->>L: visual_features (str)
L->>E: embeddings.create([visual_features, " ".join(semantic_words), context_text], dim=512)
E-->>L: [visual_emb, semantic_emb, context_emb]
L->>D: upsert {_id: code_id, ...visual, ...semantics, ...context, code_context}
D-->>L: ack
L->>WH: POST {type:"code-import", recordId, status:"success", result:{...}}
WH-->>L: 200
例外発生時:
sequenceDiagram
participant L as Lambda
participant WH as Webhook
participant SQS as SQS
L->>L: 例外をキャッチ
L->>WH: POST {type:"code-import", recordId, status:"failed"}
WH-->>L: 200(ベストエフォート)
L--xSQS: 再 raise → メッセージがキューに戻る
Note over SQS: SQS が RedrivePolicy に従ってリドライブ
11. 未確定事項 / 将来作業
| トピック | 備考 |
|---|---|
| ソースコードの長さ上限 | 暫定 200 KB。バックエンドと擦り合わせ後に強制適用。 |
| 画像フォーマット対応 | ワーカーは PNG/JPEG/GIF/WebP を受信。OpenAI vision は現状 PNG/JPEG が最良。自動変換は将来の改善項目。 |
| クロス組織検索 | vector search は organization_id + project_id で scope する。Des2Code は検索前に両方を検証する。 |