Steg 9 (R4): unified migrate-corpus.mjs --write over engineering/governance/ infrastructure/security. 327 filer mutert, verified=null, prosa byte-identisk (fra første ## seksjon), advisor urørt (0 endringer). To applier-fixes oppdaget under kjøring (TDD, RED→GREEN): - insertHeaderFields: anker faller nå tilbake når en meta-linje selv passerer 500B (2 filer pakket et avsnitt i **Status:** → Type/Source landet utenfor scan-vinduet, applierens post-write-assertion fanget + restaurerte). - normalizeStaleVerified: fjerner nå ALLE stale non-date **Verified:** i 500B-vinduet, inkl. stray body-dup rett under --- (9 mlops-genaiops-filer var ellers falskt "verified"/fresh, droppet fra worklist). Operatør-godkjent utvidelse av carve-out; kun stray metadata-linjer, aldri prosa. test-transform-criterion: precondition oppdatert til post-migrasjons-sannhet (fila bærer nå Source). Suite 728/728 grønn.
612 lines
23 KiB
Markdown
612 lines
23 KiB
Markdown
# Token Counting and Optimization Strategies
|
||
|
||
**Last updated:** 2026-06
|
||
**Status:** GA
|
||
**Category:** Cost Optimization & FinOps for AI
|
||
**Type:** reference
|
||
**Source:** https://learn.microsoft.com/azure/foundry/concepts/manage-costs
|
||
|
||
---
|
||
|
||
## Innhold
|
||
|
||
- [Introduksjon](#introduksjon)
|
||
- [Kjernekomponenter](#kjernekomponenter)
|
||
- [Arkitekturmønstre](#arkitekturmønstre)
|
||
- [Beslutningsveiledning](#beslutningsveiledning)
|
||
- [Integrasjon med Microsoft-stakken](#integrasjon-med-microsoft-stakken)
|
||
- [Offentlig sektor (Norge)](#offentlig-sektor-norge)
|
||
- [Kostnad og lisensiering](#kostnad-og-lisensiering)
|
||
- [For arkitekten (Cosmo)](#for-arkitekten-cosmo)
|
||
- [Kilder og verifisering](#kilder-og-verifisering)
|
||
|
||
## Introduksjon
|
||
|
||
Token counting og optimization er fundamentale teknikker for å kontrollere kostnader i Azure OpenAI og andre LLM-baserte løsninger. Siden fakturering baserer seg på antall tokens (både input og output), er presis måling og aktiv reduksjon av token-forbruk kritisk for økonomisk bærekraft — spesielt i høyvolum-scenarier.
|
||
|
||
**Hovedpoeng:**
|
||
- Tokens er basisenheten for prosessering — typisk ~4 tegn per token i engelsk tekst
|
||
- Kostnader påløper for både input-tokens (prompt) og output-tokens (completion)
|
||
- Ulike modeller har ulik pris per 1M tokens (typisk $2-100 USD / 1M tokens avhengig av modell)
|
||
- Prompt caching, context management og compression kan redusere kostnader med 50-90%
|
||
|
||
**Confidence:** High (basert på offisiell Microsoft-dokumentasjon)
|
||
|
||
---
|
||
|
||
## Kjernekomponenter
|
||
|
||
### Token Counting Tools
|
||
|
||
| Verktøy | Språk | Bruksområde | Nøyaktighet |
|
||
|---------|-------|-------------|-------------|
|
||
| **tiktoken** | Python, JS | OpenAI-modeller (GPT-4o, o1, o3, etc.) | Eksakt for støttede modeller |
|
||
| **Microsoft.ML.Tokenizers** | .NET/C# | Cross-model tokenisering, BPE, Tiktoken | Eksakt |
|
||
| **Hugging Face Tokenizers** | Python, JS, Java | Åpen-modell-tokenisering | Varierer per modell |
|
||
|
||
### tiktoken — Azure OpenAI Standard
|
||
|
||
```python
|
||
import tiktoken
|
||
|
||
# Encoding for GPT-4o og nyere modeller
|
||
encoding = tiktoken.get_encoding("o200k_base") # Default for gpt-4o, o1, o3
|
||
tokens = encoding.encode("Tell me about Azure AI")
|
||
token_count = len(tokens)
|
||
|
||
# Model-spesifikk encoding
|
||
try:
|
||
encoding = tiktoken.encoding_for_model("gpt-4o")
|
||
except KeyError:
|
||
encoding = tiktoken.get_encoding("o200k_base")
|
||
```
|
||
|
||
**Message Overhead Calculation:**
|
||
```python
|
||
def num_tokens_from_messages(messages, model="gpt-4o"):
|
||
"""Return the number of tokens used by a list of messages."""
|
||
try:
|
||
encoding = tiktoken.encoding_for_model(model)
|
||
except KeyError:
|
||
encoding = tiktoken.get_encoding("o200k_base")
|
||
|
||
if model in {"gpt-4o", "gpt-4o-mini", "gpt-5", "gpt-4.1", "o1", "o1-mini", "o3", "o3-mini", "o4-mini"}:
|
||
tokens_per_message = 3
|
||
tokens_per_name = 1
|
||
|
||
num_tokens = 0
|
||
for message in messages:
|
||
num_tokens += tokens_per_message
|
||
for key, value in message.items():
|
||
num_tokens += len(encoding.encode(value))
|
||
if key == "name":
|
||
num_tokens += tokens_per_name
|
||
num_tokens += 3 # every reply is primed with <|start|>assistant<|message|>
|
||
return num_tokens
|
||
```
|
||
|
||
### Microsoft.ML.Tokenizers (.NET)
|
||
|
||
```csharp
|
||
using Microsoft.ML.Tokenizers;
|
||
|
||
// Installer pakker:
|
||
// dotnet add package Microsoft.ML.Tokenizers
|
||
// dotnet add package Microsoft.ML.Tokenizers.Data.O200kBase
|
||
|
||
var tokenizer = Tokenizer.CreateTiktokenForModel("gpt-4o");
|
||
var tokens = tokenizer.CountTokens("Tell me about Azure AI");
|
||
|
||
// Trimming til token-limit
|
||
string TrimToTokenLimit(string text, int maxTokens, Tokenizer tokenizer)
|
||
{
|
||
var ids = tokenizer.Encode(text).Ids;
|
||
if (ids.Count <= maxTokens)
|
||
return text;
|
||
|
||
var trimmedIds = ids.Take(maxTokens).ToArray();
|
||
return tokenizer.Decode(trimmedIds);
|
||
}
|
||
```
|
||
|
||
### Token Usage Estimation (Azure OpenAI On Your Data)
|
||
|
||
> ⚠️ **On Your Data er deprecated og pensjoneres 2026-10-14.** Migrer til Foundry Agent Service + Foundry IQ for grounding. Token-estimering-metodikken under er fortsatt illustrativ for RAG-token-budsjettering.
|
||
|
||
```python
|
||
import tiktoken
|
||
|
||
class TokenEstimator(object):
|
||
GPT2_TOKENIZER = tiktoken.get_encoding("gpt2")
|
||
|
||
def estimate_tokens(self, text: str) -> int:
|
||
return len(self.GPT2_TOKENIZER.encode(text))
|
||
|
||
token_output = TokenEstimator().estimate_tokens(input_text)
|
||
```
|
||
|
||
**Merk:** On Your Data RAG har kompleks token-fordeling:
|
||
- **20% av context window** reservert for model response
|
||
- **80%** deles mellom meta prompt, spørsmål, conversation history og retrieved chunks
|
||
- User question og history: capped ved 2 000 tokens
|
||
- Retrieved documents: varierer basert på chunk size og antall retrieved chunks
|
||
|
||
---
|
||
|
||
## Arkitekturmønstre
|
||
|
||
### 1. Prompt Caching (Native Azure OpenAI)
|
||
|
||
**Automatisk aktivert for GPT-4o og nyere modeller**
|
||
|
||
| Parameter | Verdi | Effekt |
|
||
|-----------|-------|--------|
|
||
| Minimum prompt length | 1 024 tokens | Cache hit kan først oppnås |
|
||
| Granularitet | 128 tokens | Etter første 1024 tokens, cache hit per 128 tokens |
|
||
| Cache TTL (in-memory) | 5-10 min idle, max 1 time | Alle GPT-4o eller nyere |
|
||
| Cache TTL (extended) | Opptil 24 timer (`prompt_cache_retention: "24h"`) | GPT-5-serien + gpt-4.1; default 24h for nyere modeller |
|
||
| Kostnad (Standard) | 50% rabatt på cached tokens | Varierer per modell |
|
||
| Kostnad (Provisioned) | Opptil 100% rabatt | Inkludert i PTU-pris |
|
||
|
||
**Design-prinsipper:**
|
||
1. **Plasser repetitivt innhold først** — system messages, instructions, reference docs
|
||
2. **Bruk `prompt_cache_key`** for å påvirke routing og øke cache hit rate (NB: samme prefix + key over ~15 req/min → noen requests overflower til ekstra maskiner, og cache-effektiviteten faller)
|
||
3. **Unngå variasjon i første 1024 tokens** — én endring = cache miss
|
||
|
||
```python
|
||
response = client.chat.completions.create(
|
||
model="gpt-4o",
|
||
messages=[
|
||
{"role": "system", "content": "Long system prompt..."}, # Cached
|
||
{"role": "user", "content": "Variable user question"}
|
||
],
|
||
extra_body={"prompt_cache_key": "my-app-v1"} # Optional routing hint
|
||
)
|
||
|
||
# Response inkluderer:
|
||
# usage.prompt_tokens_details.cached_tokens
|
||
```
|
||
|
||
**Kostnad-eksempel:**
|
||
- 10 000 requests/dag med 2 000 tokens prompt
|
||
- Uten caching: 10 000 × 2 000 = 20M input tokens/dag
|
||
- Med 90% cache hit: 10 000 × 200 + (10 000 × 1 800 × 0.5) = 11M "effective" tokens
|
||
- **Besparelse: 45% på input-kostnader**
|
||
|
||
### 2. Conversation History Management
|
||
|
||
**Problem:** Chat-applikasjoner akkumulerer context over tid → økte token costs
|
||
|
||
**Løsning:** Dynamisk trimming med preservation av system message
|
||
|
||
```python
|
||
system_message = {"role": "system", "content": "You are a helpful assistant."}
|
||
max_response_tokens = 250
|
||
token_limit = 4096
|
||
conversation = [system_message]
|
||
|
||
def manage_conversation_tokens(conversation, max_response_tokens, token_limit):
|
||
while True:
|
||
user_input = input("Q: ")
|
||
conversation.append({"role": "user", "content": user_input})
|
||
|
||
conv_tokens = num_tokens_from_messages(conversation, model="gpt-4o")
|
||
|
||
# Trim oldest messages (preserve system message)
|
||
while conv_tokens + max_response_tokens >= token_limit:
|
||
del conversation[1] # Remove oldest non-system message
|
||
conv_tokens = num_tokens_from_messages(conversation, model="gpt-4o")
|
||
|
||
response = client.chat.completions.create(
|
||
model="gpt-4o",
|
||
messages=conversation,
|
||
max_tokens=max_response_tokens
|
||
)
|
||
|
||
conversation.append({
|
||
"role": "assistant",
|
||
"content": response.choices[0].message.content
|
||
})
|
||
```
|
||
|
||
**Alternative strategier:**
|
||
- **Sliding window:** Behold kun N siste turns
|
||
- **Summarization:** Compress old history til summary
|
||
- **Session reset:** Start ny conversation ved token limit
|
||
- **Responses API:** La Azure OpenAI håndtere truncation automatisk
|
||
|
||
### 3. Space-Efficient Formatting
|
||
|
||
**Token-ineffektive formater:**
|
||
```json
|
||
{"date": "January 15, 2026"} // 7 tokens
|
||
{"date": "01/15/2026"} // 9 tokens (!)
|
||
```
|
||
|
||
**Token-effektive formater:**
|
||
```
|
||
January 15, 2026 // 5 tokens
|
||
2026-01-15 // 5 tokens
|
||
|
||
| Name | Age | Role | // Tabular > JSON
|
||
| Alice | 30 | Dev |
|
||
```
|
||
|
||
**Whitespace-regler:**
|
||
- Konsekutive whitespace = separate tokens (waste)
|
||
- Leading space on word = typisk samme token
|
||
- Bruk tabeller over verbose JSON når mulig
|
||
|
||
### 4. Max Prompt/Completion Tokens (Assistants API)
|
||
|
||
```python
|
||
run = client.beta.threads.runs.create(
|
||
thread_id=thread.id,
|
||
assistant_id=assistant.id,
|
||
max_prompt_tokens=20000, # Limit context usage
|
||
max_completion_tokens=1000, # Limit output
|
||
truncation_strategy={
|
||
"type": "last_messages",
|
||
"last_messages": 10
|
||
}
|
||
)
|
||
```
|
||
|
||
**Anbefalinger:**
|
||
- **File Search:** Min. 20 000 prompt tokens, ideelt 50 000+
|
||
- **Langvarige samtaler:** Fjern `max_prompt_tokens` limit for best quality
|
||
- **Cost-sensitive apps:** Set strict limits + handle `incomplete` status
|
||
|
||
### 5. Chunking for Embeddings & RAG
|
||
|
||
**Token-limit per chunk:**
|
||
- `text-embedding-ada-002`: 8 191 tokens
|
||
- `text-embedding-3-small/large`: 8 191 tokens
|
||
|
||
```python
|
||
from langchain.text_splitter import RecursiveCharacterTextSplitter
|
||
import tiktoken
|
||
|
||
tokenizer = tiktoken.get_encoding('cl100k_base')
|
||
|
||
def tiktoken_len(text):
|
||
tokens = tokenizer.encode(text, disallowed_special=())
|
||
return len(tokens)
|
||
|
||
# Analyze document token distribution
|
||
token_counts = [tiktoken_len(page.page_content) for page in pages]
|
||
print(f"Min: {min(token_counts)}, Avg: {sum(token_counts)/len(token_counts)}, Max: {max(token_counts)}")
|
||
|
||
# Create chunks with overlap
|
||
text_splitter = RecursiveCharacterTextSplitter(
|
||
chunk_size=1000, # Target tokens
|
||
chunk_overlap=200, # Overlap for context
|
||
length_function=tiktoken_len
|
||
)
|
||
chunks = text_splitter.split_documents(pages)
|
||
```
|
||
|
||
### 6. Fine-Tuning Token Accounting
|
||
|
||
**Training cost formula (SFT/DPO):**
|
||
```
|
||
Cost = # training tokens × # epochs × price per token
|
||
```
|
||
|
||
> **RFT (Reinforcement Fine-Tuning)** bruker en *tidsbasert* kostnadsmodell (ikke token-basert) med per-job-tak på $5 000 — se «Fine-Tuning Costs» under.
|
||
|
||
**Token validation pre-training:**
|
||
```python
|
||
import json
|
||
import tiktoken
|
||
import numpy as np
|
||
|
||
encoding = tiktoken.get_encoding("o200k_base")
|
||
|
||
def num_tokens_from_messages(messages, tokens_per_message=3, tokens_per_name=1):
|
||
num_tokens = 0
|
||
for message in messages:
|
||
num_tokens += tokens_per_message
|
||
for key, value in message.items():
|
||
num_tokens += len(encoding.encode(value))
|
||
if key == "name":
|
||
num_tokens += tokens_per_name
|
||
num_tokens += 3
|
||
return num_tokens
|
||
|
||
# Validate training file
|
||
with open('training_set.jsonl', 'r', encoding='utf-8') as f:
|
||
dataset = [json.loads(line) for line in f]
|
||
|
||
total_tokens = [num_tokens_from_messages(ex["messages"]) for ex in dataset]
|
||
print(f"Mean: {np.mean(total_tokens)}, Median: {np.median(total_tokens)}")
|
||
print(f"p5 / p95: {np.quantile(total_tokens, 0.05)}, {np.quantile(total_tokens, 0.95)}")
|
||
```
|
||
|
||
**Token limits:**
|
||
- `gpt-4o-mini`: Training example max 64 536 tokens, input limit 128 000 tokens
|
||
- Overfør lange eksempler = feil ved training
|
||
- Kostnad: $2 per 1M training tokens (gpt-4.1 global, eksempel)
|
||
|
||
---
|
||
|
||
## Beslutningsveiledning
|
||
|
||
### Når skal du prioritere token optimization?
|
||
|
||
| Scenario | Anbefalt Tiltak | Forventet Besparelse |
|
||
|----------|-----------------|----------------------|
|
||
| **Høyvolum chatbot** (>10K requests/dag) | Prompt caching + conversation trimming | 40-60% input cost |
|
||
| **RAG-applikasjon** | Chunk size optimization + reranking | 30-50% total cost |
|
||
| **Long-context prompts** (>8K tokens) | Prompt caching + structured outputs | 50-90% input cost |
|
||
| **Multi-turn conversations** | Sliding window + summarization | 20-40% total cost |
|
||
| **Batch processing** | Global Standard deployment + compression | 10-30% total cost |
|
||
| **Fine-tuning** | Dataset pruning + epoch optimization | 30-60% training cost |
|
||
|
||
### Decision Tree: Optimization Strategy
|
||
|
||
```
|
||
Er prompt >1024 tokens og repetitiv?
|
||
├─ Ja → Implementer prompt caching (automatisk på GPT-4o+)
|
||
│ └─ Strukturer prompt med statisk innhold først
|
||
└─ Nei → Er det multi-turn conversation?
|
||
├─ Ja → Implementer conversation history trimming
|
||
│ └─ Sliding window eller summarization
|
||
└─ Nei → Er det RAG?
|
||
├─ Ja → Optimaliser chunk size + reranking
|
||
│ └─ Bruk strictness parameter
|
||
└─ Nei → Er output verbose/unstructured?
|
||
├─ Ja → Bruk structured outputs (JSON schema)
|
||
└─ Nei → Bruk space-efficient formatting (tabeller)
|
||
```
|
||
|
||
### Monitoring & Alerting
|
||
|
||
**Key metrics:**
|
||
- `prompt_tokens` / `completion_tokens` per request
|
||
- `cached_tokens` (prompt_tokens_details) — cache hit rate
|
||
- Cost per 1K tokens (varierer per model + deployment type)
|
||
- Total daily/monthly token consumption
|
||
|
||
**Azure Cost Management:**
|
||
- Filtrer på "Meter" for å se input/output tokens separat
|
||
- Filtrer på deployment tags for model-spesifikk cost
|
||
- Sett opp budgets med alerts (90% / 100% thresholds)
|
||
|
||
---
|
||
|
||
## Integrasjon med Microsoft-stakken
|
||
|
||
### Azure OpenAI Service
|
||
|
||
| Deployment Type | Input Token Pricing | Cached Token Discount | Output Token Pricing |
|
||
|----------------|---------------------|----------------------|---------------------|
|
||
| **Standard (Regional)** | $2.50-$100 per 1M | 50% rabatt | $10-$300 per 1M |
|
||
| **Global Standard** | 10-30% lavere | 50% rabatt | 10-30% lavere |
|
||
| **Provisioned (PTU)** | Inkludert i PTU | Opptil 100% rabatt | Inkludert i PTU |
|
||
|
||
**Merk:** Priser varierer betydelig per modell (gpt-4o vs. o1 vs. gpt-4.1)
|
||
|
||
### Microsoft Foundry
|
||
|
||
**Token Usage Estimation (On Your Data — deprecated, retires 2026-10-14):**
|
||
- Intent prompt: ~1 366 tokens (gjennomsnitt)
|
||
- Generation prompt: ~4 297 tokens (gjennomsnitt)
|
||
- Response: ~111 tokens (gjennomsnitt)
|
||
- Intent output: ~25 tokens (gjennomsnitt)
|
||
- **Total per request:** ~5 800 tokens
|
||
|
||
**Cost monitoring:**
|
||
1. Foundry portal → Operate → Overview → Estimated cost tile
|
||
2. Build → Models → Monitor tab → Token costs
|
||
3. Azure portal → Cost Management → Group by Meter
|
||
|
||
### Copilot Studio
|
||
|
||
- **Token-basert billing** for Generative Answers (Azure OpenAI)
|
||
- **Message-basert billing** for standard topics
|
||
- Token counting via `AI Builder credits` — prompt tokens + image/doc conversions
|
||
|
||
**Image token conversion:**
|
||
- Low-res (<512×512): 85 tokens flat
|
||
- High-res: Resize to 2048×2048, split into 512×512 tiles, 170 tokens per tile + 85 base
|
||
|
||
### Power Platform (AI Builder)
|
||
|
||
```
|
||
Token cost = Prompt tokens + completion tokens + image tokens
|
||
Image tokens (high-res) = (# tiles × 170) + 85
|
||
```
|
||
|
||
**Optimization:**
|
||
- Resize images før submission for å redusere tiles
|
||
- Bruk "low detail" setting når mulig
|
||
- Cache prompts i Power Automate flows
|
||
|
||
---
|
||
|
||
## Offentlig sektor (Norge)
|
||
|
||
### Compliance & Data Residency
|
||
|
||
**Token counting = metadata, ikke innhold:**
|
||
- Token-tellingen selv er ikke persondata
|
||
- Loggføring av token counts er OK for kostnadsoppfølging
|
||
- **Unngå:** Logging av faktisk prompt content uten GDPR-vurdering
|
||
|
||
**Anbefalt praksis:**
|
||
- Aggreger token metrics (daglig/ukentlig totals)
|
||
- Logg kun token counts, ikke text content
|
||
- Bruk Azure Monitor for telemetri (data residency i Norge)
|
||
|
||
### Kostnadsfordeling (Intern Fakturering)
|
||
|
||
**Tagging-strategi:**
|
||
```json
|
||
{
|
||
"tags": {
|
||
"cost_center": "IT-seksjonen",
|
||
"project": "Saksbehandling-AI",
|
||
"environment": "prod"
|
||
}
|
||
}
|
||
```
|
||
|
||
**Azure Cost Management:**
|
||
- Filtrer på tags for per-avdeling/prosjekt cost
|
||
- Eksporter cost data til Excel/Power BI for intern rapportering
|
||
- Bruk budgets med action groups for automatisk varsling
|
||
|
||
### Transparent kostnadsstyring
|
||
|
||
**Eksempel: Fylkeskommunal saksbehandling**
|
||
- Estimert 500 saker/dag × 10 000 tokens/sak = 5M tokens/dag
|
||
- Med prompt caching: 2.5M "effective" tokens/dag
|
||
- Kostnad (gpt-4o-mini, $0.15/$0.60 per 1M): ~$1/dag input + $3/dag output = **~$120/måned**
|
||
|
||
**Budsjettjustering:**
|
||
- Start med conservative estimates (worst case = no caching)
|
||
- Monitor faktisk forbruk over 1-2 måneder
|
||
- Juster deployment type (Standard vs. Provisioned) basert på volum
|
||
|
||
---
|
||
|
||
## Kostnad og lisensiering
|
||
|
||
### Azure OpenAI Pricing (verifisert juni 2026)
|
||
|
||
| Modell | Input (per 1M tokens) | Cached Input | Output (per 1M tokens) | Context Window |
|
||
|--------|-----------------------|--------------|------------------------|----------------|
|
||
| **gpt-5** | $1.25 | $0.125 | $10.00 | 400K |
|
||
| **gpt-5-mini** | $0.25 | — | $2.00 | 400K |
|
||
| **gpt-4o** | $2.50 | $1.25 | $10.00 | 128K |
|
||
| **gpt-4o-mini** | $0.15 | $0.075 | $0.60 | 128K |
|
||
| **o3-mini** | $1.10 | $0.55 | $4.40 | 200K |
|
||
| **gpt-4.1** | $2.00 | $0.50 | $8.00 | 128K |
|
||
|
||
**Merk:** Kanonisk prissannhet er `deterministic-cost-calculation-model.md` §1.1. Sjekk alltid [offisiell pricing page](https://azure.microsoft.com/pricing/details/cognitive-services/openai-service/) for din region.
|
||
|
||
### Fine-Tuning Costs
|
||
|
||
**Training (SFT/DPO):**
|
||
- Global Standard: $2 per 1M tokens (gpt-4.1, eksempel)
|
||
- Developer (spot): 50% rabatt, kan bli paused/resumed
|
||
|
||
**Training (RFT — Reinforcement Fine-Tuning):**
|
||
- Tidsbasert, IKKE token-basert: `pris = treningstid (timer) × timepris + grader-inferencing-tokens (hvis model-grader brukes)`
|
||
- Timepris: ~$100/time core training for `o4-mini-2025-04-16` (eksempel; se pricing-side for gjeldende sats)
|
||
- **Per-job-tak: $5 000** — når taket nås pauses training og et deploybart checkpoint opprettes; du kan validere og resume (videre billing uten pristak)
|
||
- Ingen kostnad for kø, failed jobs eller jobber kansellert før training starter; ved kansellering belastes arbeid frem til siste checkpoint
|
||
- Kostnadskontroll: `reasoning_effort=Low`, begrens validering/`eval_samples`, velg minste grader-modell, juster `compute_multiplier`
|
||
|
||
**Hosting:**
|
||
- $1.70/time per deployment (Standard/Global Standard)
|
||
- Påløper selv om modellen ikke brukes
|
||
- **VIKTIG:** Slett ubrukte deployments for å unngå "idle hosting cost"
|
||
|
||
**Inference:**
|
||
- Samme per-token pris som base model + hosting fee
|
||
- Developer tier: Ingen hosting fee, men deployment auto-deletes etter 24 timer
|
||
|
||
### Provisioned Throughput (PTU)
|
||
|
||
- **Flat månedlig kostnad** basert på antall PTUs
|
||
- Input/output tokens inkludert (ingen per-token cost)
|
||
- Prompt caching: Opptil 100% rabatt (effektivt "gratis" cached tokens)
|
||
- **Break-even:** Typisk ~50M tokens/måned (varierer per modell)
|
||
|
||
---
|
||
|
||
## For arkitekten (Cosmo)
|
||
|
||
### Når anbefale token optimization?
|
||
|
||
**Always recommend:**
|
||
- Prompt caching for repetitive prompts (>1024 tokens)
|
||
- Conversation history management for chatbots
|
||
- Token monitoring/budgets for alle produksjonsmiljøer
|
||
|
||
**Situational recommend:**
|
||
- **High-volume (>1M requests/måned):** Aggressive optimization (chunking, compression, structured outputs)
|
||
- **Low-volume (<100K requests/måned):** Basic optimization (caching, trimming), fokus på function over cost
|
||
- **Fine-tuning:** Dataset pruning + epoch optimization alltid (training cost accumulates fast)
|
||
|
||
### Spørsmål å stille kunden
|
||
|
||
1. **Volum:** Forventet antall requests per dag/måned?
|
||
2. **Prompt-lengde:** Gjennomsnittlig antall tokens i prompts?
|
||
3. **Repetisjon:** Hvor mye av prompten er statisk vs. dynamisk?
|
||
4. **Conversation length:** Multi-turn (chat) eller single-shot (completion)?
|
||
5. **Response length:** Trengs lange svar, eller kan det begrenses?
|
||
6. **Budsjett:** Er det hard cap på månedlige AI-kostnader?
|
||
|
||
### Implementation Checklist
|
||
|
||
- [ ] Implementer tiktoken/Microsoft.ML.Tokenizers for telemetri
|
||
- [ ] Strukturer prompts med static content først (for caching)
|
||
- [ ] Sett opp Azure Cost Management budgets + alerts
|
||
- [ ] Implementer conversation trimming (hvis multi-turn)
|
||
- [ ] Logg `cached_tokens` metric for cache hit rate monitoring
|
||
- [ ] Vurder Provisioned deployment hvis >50M tokens/måned
|
||
- [ ] Dokumenter token-fordeling i ADR (Architecture Decision Record)
|
||
|
||
### Fallgruver å unngå
|
||
|
||
| Fallgruve | Konsekvens | Løsning |
|
||
|-----------|------------|---------|
|
||
| **Ingen token monitoring** | Ukontrollerte kostnader | Sett opp Cost Management alerts ASAP |
|
||
| **Ubrukte fine-tuned deployments** | $1.70/time hosting × 24 × 30 = $1 224/måned idle | Auto-delete etter N dager uten bruk |
|
||
| **Variasjon i første 1024 tokens** | Cache miss = full input cost | Flytt dynamic content til slutten av prompt |
|
||
| **Over-chunking i RAG** | Mange små chunks = mange embeddings calls | Optimaliser chunk size (500-1500 tokens sweet spot) |
|
||
| **Manglende output limits** | Ukontrollerte completion tokens | Sett `max_tokens` parameter |
|
||
|
||
### Code Snippet: Production Token Telemetry
|
||
|
||
```python
|
||
import tiktoken
|
||
from azure.monitor.opentelemetry import configure_azure_monitor
|
||
from opentelemetry import metrics
|
||
|
||
# Configure Azure Monitor
|
||
configure_azure_monitor(connection_string="InstrumentationKey=...")
|
||
|
||
meter = metrics.get_meter(__name__)
|
||
token_counter = meter.create_counter("aoai.tokens", description="Token usage")
|
||
cost_counter = meter.create_counter("aoai.cost_usd", description="Estimated cost")
|
||
|
||
encoding = tiktoken.get_encoding("o200k_base")
|
||
|
||
def track_token_usage(prompt, completion, model="gpt-4o"):
|
||
prompt_tokens = len(encoding.encode(prompt))
|
||
completion_tokens = len(encoding.encode(completion))
|
||
|
||
# Log to Azure Monitor
|
||
token_counter.add(prompt_tokens, {"type": "input", "model": model})
|
||
token_counter.add(completion_tokens, {"type": "output", "model": model})
|
||
|
||
# Estimate cost (example rates)
|
||
input_cost = (prompt_tokens / 1_000_000) * 2.50
|
||
output_cost = (completion_tokens / 1_000_000) * 10.00
|
||
cost_counter.add(input_cost + output_cost, {"model": model})
|
||
```
|
||
|
||
---
|
||
|
||
## Kilder og verifisering
|
||
|
||
**Microsoft Learn Documentation:**
|
||
1. [Prompt caching - Azure OpenAI](https://learn.microsoft.com/en-us/azure/foundry/openai/how-to/prompt-caching) — **Verified MCP 2026-06** (in-memory + extended 24h)
|
||
2. [Work with chat completions models - Token management](https://learn.microsoft.com/en-us/azure/foundry/openai/how-to/chatgpt#manage-conversations)
|
||
3. [Plan and manage costs for Azure OpenAI](https://learn.microsoft.com/en-us/azure/foundry/concepts/manage-costs)
|
||
4. [Token counting in AI - Dynamics 365 Business Central](https://learn.microsoft.com/en-us/dynamics365/business-central/dev-itpro/developer/ai-system-app-token-counting)
|
||
5. [Use Microsoft.ML.Tokenizers for text tokenization](https://learn.microsoft.com/en-us/dotnet/ai/how-to/use-tokenizers)
|
||
6. [Azure OpenAI On Your Data - Token usage estimation](https://learn.microsoft.com/en-us/azure/foundry-classic/openai/concepts/use-your-data#token-usage-estimation-for-azure-openai-on-your-data) — ⚠️ *deprecated, retires 2026-10-14*
|
||
7. [Cost management for fine-tuning](https://learn.microsoft.com/en-us/azure/foundry/openai/how-to/fine-tuning-cost-management) — **Verified MCP 2026-06** (SFT/DPO + RFT tidsbasert + $5000-tak)
|
||
|
||
**OpenAI Resources:**
|
||
8. [OpenAI Cookbook - Token counting](https://github.com/openai/openai-cookbook/blob/main/examples/How_to_format_inputs_to_ChatGPT_models.ipynb)
|
||
9. [tiktoken GitHub repository](https://github.com/openai/tiktoken)
|
||
|
||
**Verification Date:** 2026-06
|
||
**MCP Calls:** 4 (microsoft_docs_search × 3, microsoft_docs_fetch × 2, microsoft_code_sample_search × 1)
|
||
**Confidence Level:** High — all data sourced from official Microsoft Learn documentation and verified OpenAI tooling
|