データベーススキーマの設計
open-webuiとの互換性を確保するため、以下の必須テーブルを構築します。フィールド定義は厳密に維持する必要があります。
CREATE TABLE `conversation` (
`identifier` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`user_identifier` VARCHAR(255) NOT NULL DEFAULT '',
`subject` VARCHAR(255) NOT NULL DEFAULT '',
`content_data` LONGTEXT NOT NULL,
`is_archived` TINYINT(1) UNSIGNED NOT NULL DEFAULT '0',
`shared_identifier` VARCHAR(255) NOT NULL DEFAULT '',
`created_at` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`identifier`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE `instruction` (
`identifier` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`command_key` VARCHAR(255) NOT NULL DEFAULT '',
`user_identifier` VARCHAR(255) NOT NULL DEFAULT '',
`subject` VARCHAR(255) NOT NULL DEFAULT '',
`content_body` LONGTEXT NOT NULL,
`created_at` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`identifier`),
UNIQUE KEY `command_key` (`command_key`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
モデル生成コマンド:
goctl model mysql ddl -src ./schema/conversation.sql -dir ./internal/model -c
goctl model mysql ddl -src ./schema/instruction.sql -dir ./internal/model -c
APIインターフェース実装
open-webuiとの通信要件を満たすため、厳密なエンドポイント定義が必要です。以下は再設計したAPI仕様例:
type (
NewConversationRequest {
UserIdentifier string `json:"userId"`
Subject string `json:"title"`
ContentData string `json:"chat"`
SharedId string `json:"shareId"`
IsArchived int64 `json:"archived"`
}
ConversationDetail {
Identifier int64 `json:"id"`
UserIdentifier string `json:"userId"`
Subject string `json:"title"`
ContentData string `json:"chat"`
SharedId string `json:"shareId"`
IsArchived int64 `json:"archived"`
}
ModelMetadata {
Identifier string `json:"id"`
DisplayName string `json:"name"`
ModelName string `json:"model"`
ModifiedAt string `json:"modified_at"`
SizeBytes int64 `json:"size"`
Checksum string `json:"digest"`
Architecture ModelDetail `json:"details"`
}
)
service OllamaBackend {
@handler ModelList
get /ollama/api/tags returns (ModelResponse)
@handler ChatStream
post /ollama/api/chat (ConversationEntity) returns (stream ChatResponse)
@handler ConversationCreate
post /api/v1/conversations (NewConversationRequest) returns (CreateResult)
@handler ConversationFetch
get /api/v1/conversations/:id returns (ConversationDetail)
}
API生成コマンド:
goctl api go -api ./api/ollama.api -dir ./api -style=goZero
RPCサービスの実装
内部通信用のgRPCサービスを定義します。プロトコルバッファ仕様は以下の通り:
message ConversationEntity {
string model = 1;
repeated MessageEntry messages = 2;
OptionsConfig options = 3;
}
message MessageEntry {
string role = 1;
string content = 2;
}
message ModelResponse {
repeated ModelMetadata models = 1;
}
service ModelService {
rpc GenerateStream(ConversationEntity) returns (stream CompletionChunk);
rpc FetchConversations(EmptyRequest) returns (ConversationList);
rpc RegisterInstruction(PromptInstruction) returns (OperationResult);
}
RPCスタブ生成コマンド:
goctl rpc protoc ./rpc/ollama.proto \
--go_out=./internal/types \
--go-grpc_out=./internal/types \
--zrpc_out=./rpc
設定ファイルの構成
環境依存設定をYAML形式で管理します。主要設定項目:
# APIサービス設定
Mysql:
Host: db-host.example.com
Port: 3306
DbName: ollama_core
User: service_account
Password: "secure_password"
MaxOpenConns: 100
OllamaEndpoint: "http://ollama-server:11434"
# RPCサービス設定
Etcd:
Hosts:
- "etcd-cluster:2379"
Key: model-service
CacheConfig:
RedisAddress: "cache:6379"
Database: 1
ストリーミング処理の実装
大規模言語モデルとの双方向通信を実現するため、イベント駆動型ストリーミングを採用:
func (l *ChatLogic) ProcessStream(req *types.ConversationEntity) (<-chan *types.StreamChunk, error) {
chunkStream := make(chan *types.StreamChunk, 10)
go func() {
defer close(chunkStream)
for {
select {
case chunk := <-l.ollamaClient.Generate(req):
chunkStream <- &types.StreamChunk{Content: chunk.Text}
case <-time.After(30 * time.Second):
return
}
}
}()
return chunkStream, nil
}
この実装により、サーバー送信イベント( SSE )を介したリアルタイムレスポンスが可能となります。